droptarget: Redo
authorBenjamin Otte <otte@redhat.com>
Sat, 29 Feb 2020 02:47:17 +0000 (03:47 +0100)
committerBenjamin Otte <otte@redhat.com>
Mon, 2 Mar 2020 02:18:55 +0000 (03:18 +0100)
This is a huge reorganization of GtkDropTarget. I did not know how to
split this up, so it's unfortunately all one commit.

Highlights:

- Split GtkDropTarget into GtkDropTarget and GtkDropTargetAsync
  GtkDropTarget is the simple one that only works with GTypes and offers
  a synchronous interface.
  GtkDropTargetAsync retains the full old functionality and allows
  handling mime types.

- Drop events are handled differently
  Instead of picking a single drop target and sending all DND events to
  it, every event is sent to every drop target. The first one to handle
  the event gets to call gdk_drop_status(), further handlers do not
  interact with the GdkDrop.
  Of course, for the ultimate GDK_DROP_STARTING event, only the first
  one to accept the drop gets to handle it.
  This allows stacking DND event controllers that aren't necessarily
  interested in handling the event or that might decide later to drop
  it.

- Port all widgets to either of those
  Both have a somewhat changed API due to the new event handling.
  For the ones who should use the sync version, lots of cleanup was
  involved to operate on a sync API.

35 files changed:
demos/gtk-demo/clipboard.c
docs/reference/gtk/gtk4-sections.txt
gtk/gtk.h
gtk/gtkcalendar.c
gtk/gtkcolorbutton.c
gtk/gtkcolorswatch.c
gtk/gtkdragdest.c [deleted file]
gtk/gtkdragdest.h [deleted file]
gtk/gtkdrop.c [new file with mode: 0644]
gtk/gtkdropprivate.h [new file with mode: 0644]
gtk/gtkdroptarget.c [new file with mode: 0644]
gtk/gtkdroptarget.h [new file with mode: 0644]
gtk/gtkdroptargetasync.c [new file with mode: 0644]
gtk/gtkdroptargetasync.h [new file with mode: 0644]
gtk/gtkfilechooserbutton.c
gtk/gtkfilechooserwidget.c
gtk/gtkiconview.c
gtk/gtkiconviewprivate.h
gtk/gtklistbox.c
gtk/gtkmain.c
gtk/gtknotebook.c
gtk/gtkplacessidebar.c
gtk/gtktext.c
gtk/gtktextview.c
gtk/gtktreeview.c
gtk/gtkwidget.c
gtk/gtkwindow.c
gtk/meson.build
tests/testdnd.c
tests/testdnd2.c
tests/testdnd3.c
tests/testlist3.c
tests/testnotebookdnd.c
tests/testtreednd.c
testsuite/gtk/defaultvalue.c

index 9187c94641136689b658c062100d1281ee2bca1b..1871e4a50653cc679f78a73b58f41b0405a3ce32 100644 (file)
@@ -152,43 +152,17 @@ prepare_drag (GtkDragSource *source,
   return gdk_content_provider_new_typed (GDK_TYPE_TEXTURE, paintable);
 }
 
-static void
-got_texture (GObject *source,
-             GAsyncResult *result,
-             gpointer data)
-{
-  GdkDrop *drop = GDK_DROP (source);
-  GtkWidget *image = data;
-  const GValue *value;
-  GError *error = NULL;
-
-  value = gdk_drop_read_value_finish (drop, result, &error);
-  if (value)
-    {
-      GdkTexture *texture = g_value_get_object (value);
-      gtk_image_set_from_paintable (GTK_IMAGE (image), GDK_PAINTABLE (texture));
-    }
-  else
-    {
-      g_print ("Failed to get data: %s\n", error->message);
-      g_error_free (error);
-    }
-}
-
 static gboolean
 drag_drop (GtkDropTarget *dest,
-           GdkDrop       *drop,
-           int            x,
-           int            y,
-           GtkWidget     *widget)
+           const GValue  *value,
+           double         x,
+           double         y,
+           GtkImage      *image)
 {
-  if (gdk_drop_has_value (drop, GDK_TYPE_TEXTURE))
-    {
-      gdk_drop_read_value_async (drop, GDK_TYPE_TEXTURE, G_PRIORITY_DEFAULT, NULL, got_texture, widget);
-      return TRUE;
-    }
+  GdkTexture *texture = g_value_get_object (value);
+  gtk_image_set_from_paintable (GTK_IMAGE (image), GDK_PAINTABLE (texture));
 
-  return FALSE;
+  return TRUE;
 }
 
 static void
@@ -354,8 +328,8 @@ do_clipboard (GtkWidget *do_widget)
       gtk_widget_add_controller (image, GTK_EVENT_CONTROLLER (source));
 
       /* accept drops on image */
-      dest = gtk_drop_target_new (gdk_content_formats_new_for_gtype (GDK_TYPE_TEXTURE), GDK_ACTION_COPY);
-      g_signal_connect (dest, "drag-drop", G_CALLBACK (drag_drop), image);
+      dest = gtk_drop_target_new (GDK_TYPE_TEXTURE, GDK_ACTION_COPY);
+      g_signal_connect (dest, "drop", G_CALLBACK (drag_drop), image);
       gtk_widget_add_controller (image, GTK_EVENT_CONTROLLER (dest));
 
       /* context menu on image */
@@ -383,8 +357,8 @@ do_clipboard (GtkWidget *do_widget)
       gtk_widget_add_controller (image, GTK_EVENT_CONTROLLER (source));
 
       /* accept drops on image */
-      dest = gtk_drop_target_new (gdk_content_formats_new_for_gtype (GDK_TYPE_TEXTURE), GDK_ACTION_COPY);
-      g_signal_connect (dest, "drag-drop", G_CALLBACK (drag_drop), image);
+      dest = gtk_drop_target_new (GDK_TYPE_TEXTURE, GDK_ACTION_COPY);
+      g_signal_connect (dest, "drop", G_CALLBACK (drag_drop), image);
       gtk_widget_add_controller (image, GTK_EVENT_CONTROLLER (dest));
 
       /* context menu on image */
index 008ab81f1eb04f307ff8009600a42484fe46ddc5..08dc019e08b1cfe81fabf6ff4a1bde450b688113 100644 (file)
@@ -6813,14 +6813,16 @@ gtk_drag_source_get_type
 <FILE>gtkdroptarget</FILE>
 GtkDropTarget
 gtk_drop_target_new
-gtk_drop_target_set_formats
+gtk_drop_target_set_gtypes
+gtk_drop_target_get_gtypes
 gtk_drop_target_get_formats
 gtk_drop_target_set_actions
 gtk_drop_target_get_actions
+gtk_drop_target_set_preload
+gtk_drop_target_get_preload
 gtk_drop_target_get_drop
-gtk_drop_target_find_mimetype
-gtk_drag_highlight
-gtk_drag_unhighlight
+gtk_drop_target_get_value
+gtk_drop_target_reject
 
 <SUBSECTION Standard>
 GTK_TYPE_DROP_TARGET
@@ -6833,6 +6835,27 @@ GTK_DROP_TARGET_GET_CLASS
 gtk_drop_target_get_type
 </SECTION>
 
+<SECTION>
+<FILE>gtkdroptargetasync</FILE>
+GtkDropTargetAsync
+gtk_drop_target_async_new
+gtk_drop_target_async_set_formats
+gtk_drop_target_async_get_formats
+gtk_drop_target_async_set_actions
+gtk_drop_target_async_get_actions
+gtk_drop_target_async_reject_drop
+
+<SUBSECTION Standard>
+GTK_TYPE_DROP_TARGET_ASYNC
+GTK_DROP_TARGET_ASYNC
+GTK_DROP_TARGET_ASYNC_CLASS
+GTK_IS_DROP_TARGET_ASYNC
+GTK_IS_DROP_TARGET_ASYNC_CLASS
+GTK_DROP_TARGET_ASYNC_GET_CLASS
+<SUBSECTION Private>
+gtk_drop_target_async_get_type
+</SECTION>
+
 <SECTION>
 <FILE>gtkdropcontrollermotion</FILE>
 <TITLE>GtkDropControllerMotion</TITLE>
index 8ee2ba1b0b8cebd2a5903245960a63c41efdf68e..603fe9f9fd6e172cebd1401d52d5b412d5b97988 100644 (file)
--- a/gtk/gtk.h
+++ b/gtk/gtk.h
 #include <gtk/gtkcustomlayout.h>
 #include <gtk/gtkdebug.h>
 #include <gtk/gtkdialog.h>
-#include <gtk/gtkdragdest.h>
 #include <gtk/gtkdragicon.h>
 #include <gtk/gtkdragsource.h>
 #include <gtk/gtkdrawingarea.h>
 #include <gtk/gtkdropcontrollermotion.h>
+#include <gtk/gtkdroptarget.h>
+#include <gtk/gtkdroptargetasync.h>
 #include <gtk/gtkeditable.h>
 #include <gtk/gtkemojichooser.h>
 #include <gtk/gtkentry.h>
index eb63b38db04157a585d5b2a138adad3fa2a180e0..ec71a373ccee936ea6fda9c30b9f7e00e122832c 100644 (file)
@@ -95,7 +95,7 @@
 #endif
 
 #include "gtkcalendar.h"
-#include "gtkdragdest.h"
+#include "gtkdroptarget.h"
 #include "gtkintl.h"
 #include "gtkmain.h"
 #include "gtkmarshalers.h"
@@ -285,17 +285,6 @@ static void     gtk_calendar_focus_controller_focus     (GtkEventController    *
                                                          GtkWidget             *widget);
 static void     gtk_calendar_state_flags_changed  (GtkWidget     *widget,
                                                    GtkStateFlags  previous_state);
-static gboolean gtk_calendar_drag_accept        (GtkDropTarget    *dest,
-                                                 GdkDrop          *drop,
-                                                 GtkCalendar      *calendar);
-static void     gtk_calendar_drag_leave         (GtkDropTarget    *dest,
-                                                 GdkDrop          *drop,
-                                                 GtkCalendar      *calendar);
-static gboolean gtk_calendar_drag_drop          (GtkDropTarget    *dest,
-                                                 GdkDrop          *drop,
-                                                 int               x,
-                                                 int               y,
-                                                 GtkCalendar      *calendar);
 
 
 static void calendar_invalidate_day     (GtkCalendar *widget,
@@ -320,6 +309,57 @@ static char    *default_monthname[12];
 
 G_DEFINE_TYPE_WITH_PRIVATE (GtkCalendar, gtk_calendar, GTK_TYPE_WIDGET)
 
+static void
+gtk_calendar_drag_notify_value (GtkDropTarget  *target,
+                                GParamSpec    **pspec,
+                                GtkCalendar    *calendar)
+{
+  GDate *date;
+  const GValue *value;
+
+  value = gtk_drop_target_get_value (target);
+  if (value == NULL)
+    return;
+
+  date = g_date_new ();
+  g_date_set_parse (date, g_value_get_string (value));
+  if (!g_date_valid (date))
+    gtk_drop_target_reject (target);
+  g_date_free (date);
+}
+
+static gboolean
+gtk_calendar_drag_drop (GtkDropTarget  *dest,
+                        const GValue   *value,
+                        double          x,
+                        double          y,
+                        GtkCalendar    *calendar)
+{
+  GDate *date;
+  GDateTime *datetime;
+
+  date = g_date_new ();
+  g_date_set_parse (date, g_value_get_string (value));
+
+  if (!g_date_valid (date))
+    {
+      g_warning ("Received invalid date data");
+      g_date_free (date);
+      return FALSE;
+    }
+
+  datetime = g_date_time_new_local (g_date_get_year (date),
+                                    g_date_get_month (date),
+                                    g_date_get_day (date),
+                                    0, 0, 0);
+  g_date_free (date);
+
+  gtk_calendar_select_day (calendar, datetime);
+  g_date_time_unref (datetime);
+
+  return TRUE;
+}
+
 static void
 gtk_calendar_dispose (GObject *object)
 {
@@ -518,6 +558,7 @@ gtk_calendar_init (GtkCalendar *calendar)
   GtkWidget *widget = GTK_WIDGET (calendar);
   GtkEventController *controller;
   GtkGesture *gesture;
+  GtkDropTarget *target;
   gint i;
 #ifdef G_OS_WIN32
   wchar_t wbuffer[100];
@@ -535,7 +576,6 @@ gtk_calendar_init (GtkCalendar *calendar)
 #else
   gchar *week_start;
 #endif
-  GtkDropTarget *dest;
   int min_year_width;
   GDateTime *now;
 
@@ -718,14 +758,11 @@ gtk_calendar_init (GtkCalendar *calendar)
 
   priv->in_drag = 0;
 
-  dest = gtk_drop_target_new (gdk_content_formats_new_for_gtype (G_TYPE_STRING),
-                              GDK_ACTION_COPY);
-
-  g_signal_connect (dest, "accept", G_CALLBACK (gtk_calendar_drag_accept), calendar);
-  g_signal_connect (dest, "drag-leave", G_CALLBACK (gtk_calendar_drag_leave), calendar);
-  g_signal_connect (dest, "drag-drop", G_CALLBACK (gtk_calendar_drag_drop), calendar);
-
-  gtk_widget_add_controller (widget, GTK_EVENT_CONTROLLER (dest));
+  target = gtk_drop_target_new (G_TYPE_STRING, GDK_ACTION_COPY);
+  gtk_drop_target_set_preload (target, TRUE);
+  g_signal_connect (target, "notify::value", G_CALLBACK (gtk_calendar_drag_notify_value), calendar);
+  g_signal_connect (target, "drop", G_CALLBACK (gtk_calendar_drag_drop), calendar);
+  gtk_widget_add_controller (widget, GTK_EVENT_CONTROLLER (target));
 
   priv->year_before = 0;
 
@@ -1417,139 +1454,6 @@ gtk_calendar_state_flags_changed (GtkWidget     *widget,
     }
 }
 
-/* Get/set whether drag_motion requested the drag data and
- * drag_data_received should thus not actually insert the data,
- * since the data doesn’t result from a drop.
- */
-static void
-set_status_pending (GdkDrop       *drop,
-                    GdkDragAction  suggested_action)
-{
-  g_object_set_data (G_OBJECT (drop),
-                     I_("gtk-calendar-status-pending"),
-                     GINT_TO_POINTER (suggested_action));
-}
-
-static GdkDragAction
-get_status_pending (GdkDrop *drop)
-{
-  return GPOINTER_TO_INT (g_object_get_data (G_OBJECT (drop),
-                                             "gtk-calendar-status-pending"));
-}
-
-static void
-gtk_calendar_drag_leave (GtkDropTarget *dest,
-                         GdkDrop       *drop,
-                         GtkCalendar   *calendar)
-{
-}
-
-static void
-got_text (GObject      *source,
-          GAsyncResult *result,
-          gpointer      data)
-{
-  GtkDropTarget *dest = GTK_DROP_TARGET (data);
-  GtkCalendar *calendar = GTK_CALENDAR (gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (dest)));
-  GdkDrop *drop = GDK_DROP (source);
-  gchar *str;
-  GDate *date;
-  GDateTime *datetime;
-  GdkDragAction suggested_action;
-
-  suggested_action = get_status_pending (drop);
-  set_status_pending (drop, 0);
-
-  str = gdk_drop_read_text_finish (drop, result, NULL);
-
-  if (suggested_action)
-    {
-      if (str)
-        {
-          date = g_date_new ();
-          g_date_set_parse (date, str);
-          if (!g_date_valid (date))
-              suggested_action = 0;
-          g_date_free (date);
-          g_free (str);
-        }
-      else
-        suggested_action = 0;
-      gdk_drop_status (drop, suggested_action);
-      if (suggested_action == 0)
-        gtk_drop_target_deny_drop (dest, drop);
-      return;
-    }
-
-  date = g_date_new ();
-  if (str)
-    {
-      g_date_set_parse (date, str);
-      g_free (str);
-    }
-
-  if (!g_date_valid (date))
-    {
-      g_warning ("Received invalid date data");
-      g_date_free (date);
-      gdk_drop_finish (drop, 0);
-      gtk_drop_target_deny_drop (dest, drop);
-      return;
-    }
-
-  datetime = g_date_time_new_local (g_date_get_year (date),
-                                    g_date_get_month (date),
-                                    g_date_get_day (date),
-                                    0, 0, 0);
-  g_date_free (date);
-
-  gdk_drop_finish (drop, suggested_action);
-
-  gtk_calendar_select_day (calendar, datetime);
-  g_date_time_unref (datetime);
-}
-
-static gboolean
-gtk_calendar_drag_accept (GtkDropTarget *dest,
-                          GdkDrop       *drop,
-                          GtkCalendar   *calendar)
-{
-  const char *target;
-
-  target = gtk_drop_target_find_mimetype (dest);
-  if (!target || gdk_drop_get_actions (drop) == 0)
-    {
-      gdk_drop_status (drop, 0);
-      return FALSE;
-    }
-  else if (get_status_pending (drop) == 0)
-    {
-      set_status_pending (drop, gdk_drop_get_actions (drop));
-      gdk_drop_read_text_async (drop, NULL, got_text, dest);
-    }
-  return TRUE;
-}
-
-static gboolean
-gtk_calendar_drag_drop (GtkDropTarget  *dest,
-                        GdkDrop        *drop,
-                        int             x,
-                        int             y,
-                        GtkCalendar    *calendar)
-{
-  const char *target;
-
-  target = gtk_drop_target_find_mimetype (dest);
-  if (target != NULL)
-    {
-      set_status_pending (drop, 0);
-      gdk_drop_read_text_async (drop, NULL, got_text, dest);
-      return TRUE;
-    }
-
-  return FALSE;
-}
-
 \f
 /****************************************
  *              Public API              *
index 9c951d21aed9c1c1322a06d5a90b61e4067ef773..17f52fba7d0c6f2be80735f593938825e6ebff28 100644 (file)
 #include "gtkcolorchooserprivate.h"
 #include "gtkcolorchooserdialog.h"
 #include "gtkcolorswatchprivate.h"
-#include "gtkdragdest.h"
 #include "gtkdragsource.h"
+#include "gtkdroptarget.h"
 #include "gtkintl.h"
 #include "gtkmain.h"
 #include "gtkmarshalers.h"
 #include "gtkprivate.h"
 #include "gtksnapshot.h"
 #include "gtkstylecontext.h"
-#include "gtkdragsource.h"
-#include "gtkdragdest.h"
-#include "gtkeventcontroller.h"
 
 
 /**
@@ -230,33 +227,16 @@ gtk_color_button_class_init (GtkColorButtonClass *klass)
   gtk_widget_class_set_css_name (widget_class, "colorbutton");
 }
 
-static void
-got_color (GObject      *source,
-           GAsyncResult *result,
-           gpointer      data)
-{
-  GdkDrop *drop = GDK_DROP (source);
-  const GValue *value;
-
-  value = gdk_drop_read_value_finish (drop, result, NULL);
-  if (value)
-    {
-      GdkRGBA *color = g_value_get_boxed (value);
-      gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (data), color);
-      gdk_drop_finish (drop, GDK_ACTION_COPY);
-    }
-  else
-    gdk_drop_finish (drop, 0);
-}
-
 static gboolean
-gtk_color_button_drag_drop (GtkDropTarget  *dest,
-                            GdkDrop        *drop,
-                            int             x,
-                            int             y,
-                            GtkColorButton *button)
+gtk_color_button_drop (GtkDropTarget  *dest,
+                       const GValue   *value,
+                       double          x,
+                       double          y,
+                       GtkColorButton *button)
 {
-  gdk_drop_read_value_async (drop, GDK_TYPE_RGBA, G_PRIORITY_DEFAULT, NULL, got_color, button);
+  GdkRGBA *color = g_value_get_boxed (value);
+
+  gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (button), color);
   return TRUE;
 }
 
@@ -320,9 +300,8 @@ gtk_color_button_init (GtkColorButton *button)
   priv->rgba.alpha = 1;
   priv->use_alpha = FALSE;
 
-  dest = gtk_drop_target_new (gdk_content_formats_new_for_gtype (GDK_TYPE_RGBA),
-                              GDK_ACTION_COPY);
-  g_signal_connect (dest, "drag-drop", G_CALLBACK (gtk_color_button_drag_drop), button);
+  dest = gtk_drop_target_new (GDK_TYPE_RGBA, GDK_ACTION_COPY);
+  g_signal_connect (dest, "drop", G_CALLBACK (gtk_color_button_drop), button);
   gtk_widget_add_controller (GTK_WIDGET (button), GTK_EVENT_CONTROLLER (dest));
 
   source = gtk_drag_source_new ();
index f073a7ff68e01bfc4527eef2c5adc2ab72d083d4..ae424ad5721625b403b7362082745024daae14d7 100644 (file)
@@ -22,8 +22,8 @@
 #include "gtkbox.h"
 #include "gtkcolorchooserprivate.h"
 #include "gtkcssnodeprivate.h"
-#include "gtkdragdest.h"
 #include "gtkdragsource.h"
+#include "gtkdroptarget.h"
 #include "gtkgesturelongpress.h"
 #include "gtkgestureclick.h"
 #include "gtkgesturesingle.h"
@@ -133,33 +133,16 @@ gtk_color_swatch_drag_begin (GtkDragSource  *source,
   g_object_unref (paintable);
 }
 
-static void
-got_color (GObject      *source,
-           GAsyncResult *result,
-           gpointer      data)
-{
-  GdkDrop *drop = GDK_DROP (source);
-  const GValue *value;
-
-  value = gdk_drop_read_value_finish (drop, result, NULL);
-  if (value)
-    {
-      GdkRGBA *color = g_value_get_boxed (value);
-      gtk_color_swatch_set_rgba (GTK_COLOR_SWATCH (data), color);
-      gdk_drop_finish (drop, GDK_ACTION_COPY);
-    }
-  else
-    gdk_drop_finish (drop, 0);
-}
-
 static gboolean
 swatch_drag_drop (GtkDropTarget  *dest,
-                  GdkDrop        *drop,
-                  int             x,
-                  int             y,
+                  const GValue   *value,
+                  double          x,
+                  double          y,
                   GtkColorSwatch *swatch)
+
 {
-  gdk_drop_read_value_async (drop, GDK_TYPE_RGBA, G_PRIORITY_DEFAULT, NULL, got_color, swatch);
+  gtk_color_swatch_set_rgba (swatch, g_value_get_boxed (value));
+
   return TRUE;
 }
 
@@ -670,9 +653,8 @@ gtk_color_swatch_set_can_drop (GtkColorSwatch *swatch,
 
   if (can_drop && !priv->dest)
     {
-      priv->dest = gtk_drop_target_new (gdk_content_formats_new_for_gtype (GDK_TYPE_RGBA),
-                                        GDK_ACTION_COPY);
-      g_signal_connect (priv->dest, "drag-drop", G_CALLBACK (swatch_drag_drop), swatch);
+      priv->dest = gtk_drop_target_new (GDK_TYPE_RGBA, GDK_ACTION_COPY);
+      g_signal_connect (priv->dest, "drop", G_CALLBACK (swatch_drag_drop), swatch);
       gtk_widget_add_controller (GTK_WIDGET (swatch), GTK_EVENT_CONTROLLER (priv->dest));
     }
   if (!can_drop && priv->dest)
diff --git a/gtk/gtkdragdest.c b/gtk/gtkdragdest.c
deleted file mode 100644 (file)
index 7f80e5a..0000000
+++ /dev/null
@@ -1,871 +0,0 @@
-/* GTK - The GIMP Toolkit
- * Copyright (C) 1995-1999 Peter Mattis, Spencer Kimball and Josh MacDonald
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/*
- * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
- * file for a list of people on the GTK+ Team.  See the ChangeLog
- * files for a list of changes.  These files are distributed with
- * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
- */
-
-#include "config.h"
-
-#include "gtkdragdest.h"
-#include "gtkdragdestprivate.h"
-
-#include "gtkintl.h"
-#include "gtknative.h"
-#include "gtktypebuiltins.h"
-#include "gtkeventcontrollerprivate.h"
-#include "gtkmarshalers.h"
-
-
-/**
- * SECTION:gtkdroptarget
- * @Short_description: Event controller to receive DND drops
- * @Title: GtkDropTarget
- *
- * GtkDropTarget is an auxiliary object that is used to receive
- * Drag-and-Drop operations.
- *
- * To use a GtkDropTarget to receive drops on a widget, you create
- * a GtkDropTarget object, configure which data formats and actions
- * you support, connect to its signals, and then attach
- * it to the widget with gtk_widget_add_controller().
- *
- * During a drag operation, the first signal that a GtkDropTarget
- * emits is #GtkDropTarget::accept, which is meant to determine
- * whether the target is a possible drop site for the ongoing drag.
- * The default handler for the ::accept signal accepts the drag
- * if it finds a compatible data format an an action that is supported
- * on both sides.
- *
- * If it is, and the widget becomes the current target, you will
- * receive a #GtkDropTarget::drag-enter signal, followed by
- * #GtkDropTarget::drag-motion signals as the pointer moves, and
- * finally either a #GtkDropTarget::drag-leave signal when the pointer
- * move off the widget, or a #GtkDropTarget::drag-drop signal when
- * a drop happens.
- *
- * The ::drag-enter and ::drag-motion handler can call gdk_drop_status()
- * to update the status of the ongoing operation. The ::drag-drop handler
- * should initiate the data transfer and finish the operation by calling
- * gdk_drop_finish().
- *
- * Between the ::drag-enter and ::drag-leave signals the widget is the
- * current drop target, and will receive the %GTK_STATE_FLAG_DROP_ACTIVE
- * state, which can be used to style the widget as a drop targett.
- */
-
-struct _GtkDropTarget
-{
-  GtkEventController parent_object;
-
-  GdkContentFormats *formats;
-  GdkDragAction actions;
-
-  GtkWidget *widget;
-  GdkDrop *drop;
-  gboolean contains;
-  gboolean contains_pending;
-};
-
-struct _GtkDropTargetClass
-{
-  GtkEventControllerClass parent_class;
-
-  gboolean (*accept ) (GtkDropTarget *dest,
-                       GdkDrop       *drop);
-};
-
-enum {
-  PROP_FORMATS = 1,
-  PROP_ACTIONS,
-  PROP_CONTAINS,
-  NUM_PROPERTIES
-};
-
-static GParamSpec *properties[NUM_PROPERTIES];
-
-enum {
-  ACCEPT,
-  DRAG_ENTER,
-  DRAG_MOTION,
-  DRAG_LEAVE,
-  DRAG_DROP,
-  NUM_SIGNALS
-};
-
-static guint signals[NUM_SIGNALS];
-
-static gboolean gtk_drop_target_accept (GtkDropTarget *dest,
-                                        GdkDrop       *drop);
-
-static gboolean gtk_drop_target_handle_event (GtkEventController *controller,
-                                              GdkEvent           *event,
-                                              double              x,
-                                              double              y);
-static gboolean gtk_drop_target_filter_event (GtkEventController *controller,
-                                              GdkEvent           *event);
-
-static gboolean gtk_drop_target_get_contains (GtkDropTarget *dest);
-static void     gtk_drop_target_set_contains (GtkDropTarget *dest,
-                                              gboolean       contains);
-
-typedef enum {
-  GTK_DROP_STATUS_NONE,
-  GTK_DROP_STATUS_ACCEPTED,
-  GTK_DROP_STATUS_DENIED
-} GtkDropStatus;
-
-static GtkDropStatus gtk_drop_target_get_drop_status (GtkDropTarget *dest,
-                                                      GdkDrop       *drop);
-static void          gtk_drop_target_set_drop_status (GtkDropTarget *dest,
-                                                      GdkDrop       *drop,
-                                                      GtkDropStatus  status);
-
-G_DEFINE_TYPE (GtkDropTarget, gtk_drop_target, GTK_TYPE_EVENT_CONTROLLER);
-
-static void
-gtk_drop_target_init (GtkDropTarget *dest)
-{
-}
-
-static void
-gtk_drop_target_finalize (GObject *object)
-{
-  GtkDropTarget *dest = GTK_DROP_TARGET (object);
-
-  g_clear_pointer (&dest->formats, gdk_content_formats_unref);
-
-  G_OBJECT_CLASS (gtk_drop_target_parent_class)->finalize (object);
-}
-
-static void
-gtk_drop_target_set_property (GObject      *object,
-                            guint         prop_id,
-                            const GValue *value,
-                            GParamSpec   *pspec)
-{
-  GtkDropTarget *dest = GTK_DROP_TARGET (object);
-
-  switch (prop_id)
-    {
-    case PROP_FORMATS:
-      gtk_drop_target_set_formats (dest, g_value_get_boxed (value));
-      break;
-
-    case PROP_ACTIONS:
-      gtk_drop_target_set_actions (dest, g_value_get_flags (value));
-      break;
-
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-    }
-}
-
-static void
-gtk_drop_target_get_property (GObject    *object,
-                            guint       prop_id,
-                            GValue     *value,
-                            GParamSpec *pspec)
-{
-  GtkDropTarget *dest = GTK_DROP_TARGET (object);
-
-  switch (prop_id)
-    {
-    case PROP_FORMATS:
-      g_value_set_boxed (value, gtk_drop_target_get_formats (dest));
-      break;
-
-    case PROP_ACTIONS:
-      g_value_set_flags (value, gtk_drop_target_get_actions (dest));
-      break;
-
-    case PROP_CONTAINS:
-      g_value_set_boolean (value, gtk_drop_target_get_contains (dest));
-      break;
-
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-    }
-}
-
-static void
-gtk_drop_target_class_init (GtkDropTargetClass *class)
-{
-  GObjectClass *object_class = G_OBJECT_CLASS (class);
-  GtkEventControllerClass *controller_class = GTK_EVENT_CONTROLLER_CLASS (class);
-
-  object_class->finalize = gtk_drop_target_finalize;
-  object_class->set_property = gtk_drop_target_set_property;
-  object_class->get_property = gtk_drop_target_get_property;
-
-  controller_class->handle_event = gtk_drop_target_handle_event;
-  controller_class->filter_event = gtk_drop_target_filter_event;
-
-  class->accept = gtk_drop_target_accept;
-
-  /**
-   * GtkDropTarget:formats:
-   *
-   * The #GdkContentFormats that determines the supported data formats
-   */
-  properties[PROP_FORMATS] =
-       g_param_spec_boxed ("formats", P_("Formats"), P_("Formats"),
-                           GDK_TYPE_CONTENT_FORMATS,
-                           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
-
-  /**
-   * GtkDropTarget:actions:
-   *
-   * The #GdkDragActions that this drop target supports
-   */ 
-  properties[PROP_ACTIONS] =
-       g_param_spec_flags ("actions", P_("Actions"), P_("Actions"),
-                           GDK_TYPE_DRAG_ACTION, 0,
-                           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
-
-  /**
-   * GtkDropTarget:contains:
-   *
-   * Whether the drop target is currently the targed of an ongoing drag operation,
-   * and highlighted.
-   */
-  properties[PROP_CONTAINS] =
-       g_param_spec_boolean ("contains", P_("Contains an ongoing drag"), P_("Contains the current drag"),
-                             FALSE,
-                             G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
-
-  g_object_class_install_properties (object_class, NUM_PROPERTIES, properties);
-
-  /**
-   * GtkDropTarget::drag-enter:
-   * @dest: the #GtkDropTarget
-   * @drop: the #GdkDrop
-   *
-   * The ::drag-enter signal is emitted on the drop site when the cursor
-   * enters the widget. It can be used to set up custom highlighting.
-   */
-  signals[DRAG_ENTER] =
-      g_signal_new (I_("drag-enter"),
-                    G_TYPE_FROM_CLASS (class),
-                    G_SIGNAL_RUN_LAST,
-                    0,
-                    NULL, NULL,
-                    NULL,
-                    G_TYPE_NONE, 1,
-                    GDK_TYPE_DROP);
-
-  /**
-   * GtkDropTarget::drag-leave:
-   * @dest: the #GtkDropTarget
-   * @drop: the #GdkDrop
-   *
-   * The ::drag-leave signal is emitted on the drop site when the cursor
-   * leaves the widget. Its main purpose it to undo things done in
-   * #GtkDropTarget::drag-enter.
-   */
-  signals[DRAG_LEAVE] =
-      g_signal_new (I_("drag-leave"),
-                    G_TYPE_FROM_CLASS (class),
-                    G_SIGNAL_RUN_LAST,
-                    0,
-                    NULL, NULL,
-                    NULL,
-                    G_TYPE_NONE, 1,
-                    GDK_TYPE_DROP);
-
-  /**
-   * GtkDropTarget::drag-motion:
-   * @dest: the #GtkDropTarget
-   * @drop: the #GdkDrop
-   * @x: the x coordinate of the current cursor position
-   * @y: the y coordinate of the current cursor position
-   *
-   * The ::drag motion signal is emitted while the pointer is moving
-   * over the drop target.
-   */
-  signals[DRAG_MOTION] =
-      g_signal_new (I_("drag-motion"),
-                    G_TYPE_FROM_CLASS (class),
-                    G_SIGNAL_RUN_LAST,
-                    0,
-                    NULL, NULL,
-                    NULL,
-                    G_TYPE_NONE, 3,
-                    GDK_TYPE_DROP, G_TYPE_INT, G_TYPE_INT);
-
- /**
-   * GtkWidget::accept:
-   * @dest: the #GtkDropTarget
-   * @drop: the #GdkDrop
-   *
-   * The ::accept signal is emitted on the drop site when the user
-   * moves the cursor over the widget during a drag. The signal handler
-   * must determine whether the cursor position is in a drop zone or not.
-   * If it is not in a drop zone, it returns %FALSE and no further processing
-   * is necessary. Otherwise, the handler returns %TRUE. In this case, the
-   * handler is responsible for providing the necessary information for
-   * displaying feedback to the user, by calling gdk_drag_status().
-   *
-   * The default handler for this signal decides whether to accept the drop
-   * based on the type of the data.
-   *
-   * If the decision whether the drop will be accepted or rejected can't be
-   * made based solely the data format, handler may inspect the dragged data
-   * by calling one of the #GdkDrop read functions and return %TRUE to
-   * tentatively accept the drop. When the data arrives and is found to not be
-   * acceptable, a call to gtk_drop_target_deny_drop() should be made to reject
-   * the drop.
-   *
-   * Returns: whether the cursor position is in a drop zone
-   */
-  signals[ACCEPT] =
-      g_signal_new (I_("accept"),
-                    G_TYPE_FROM_CLASS (class),
-                    G_SIGNAL_RUN_LAST,
-                    G_STRUCT_OFFSET (GtkDropTargetClass, accept),
-                    g_signal_accumulator_first_wins, NULL,
-                    NULL,
-                    G_TYPE_BOOLEAN, 1,
-                    GDK_TYPE_DROP);
-
-  /**
-   * GtkDropTarget::drag-drop:
-   * @dest: the #GtkDropTarget
-   * @drop: the #GdkDrop
-   * @x: the x coordinate of the current cursor position
-   * @y: the y coordinate of the current cursor position
-   *
-   * The ::drag-drop signal is emitted on the drop site when the user drops
-   * the data onto the widget. The signal handler must determine whether
-   * the cursor position is in a drop zone or not. If it is not in a drop
-   * zone, it returns %FALSE and no further processing is necessary.
-   *
-   * Otherwise, the handler returns %TRUE. In this case, the handler must
-   * ensure that gdk_drop_finish() is called to let the source know that
-   * the drop is done. The call to gtk_drag_finish() can be done either
-   * directly or after receiving the data.
-   *
-   * To receive the data, use one of the read functions provides by #GtkDrop
-   * and #GtkDragDest: gdk_drop_read_async(), gdk_drop_read_value_async(),
-   * gdk_drop_read_text_async().
-   *
-   * You can use gtk_drop_target_get_drop() to obtain the #GtkDrop object
-   * for the ongoing operation in your signal handler. If you call one of the
-   * read functions in your handler, GTK will ensure that the #GtkDrop object
-   * stays alive until the read is completed. If you delay obtaining the data
-   * (e.g. to handle %GDK_ACTION_ASK by showing a #GtkPopover), you need to
-   * hold a reference on the #GtkDrop.
-   *
-   * Returns: whether the cursor position is in a drop zone
-   */
-  signals[DRAG_DROP] =
-      g_signal_new (I_("drag-drop"),
-                    G_TYPE_FROM_CLASS (class),
-                    G_SIGNAL_RUN_LAST,
-                    0,
-                    NULL, NULL,
-                    NULL,
-                    G_TYPE_BOOLEAN, 3,
-                    GDK_TYPE_DROP, G_TYPE_INT, G_TYPE_INT);
-}
-
-/**
- * gtk_drop_target_new:
- * @formats: (nullable) (transfer full): the supported data formats
- * @actions: the supported actions
- *
- * Creates a new #GtkDropTarget object.
- *
- * Returns: the new #GtkDropTarget
- */
-GtkDropTarget *
-gtk_drop_target_new (GdkContentFormats *formats,
-                     GdkDragAction      actions)
-{
-  GtkDropTarget *result;
-
-  result = g_object_new (GTK_TYPE_DROP_TARGET,
-                         "formats", formats,
-                         "actions", actions,
-                         NULL);
-
-  g_clear_pointer (&formats, gdk_content_formats_unref);
-
-  return result;
-}
-
-/**
- * gtk_drop_target_set_formats:
- * @dest: a #GtkDropTarget
- * @formats: (nullable): the supported data formats
- *
- * Sets the data formats that this drop target will accept.
- */
-void
-gtk_drop_target_set_formats (GtkDropTarget     *dest,
-                             GdkContentFormats *formats)
-{
-  g_return_if_fail (GTK_IS_DROP_TARGET (dest));
-
-  if (dest->formats == formats)
-    return;
-
-  if (dest->formats)
-    gdk_content_formats_unref (dest->formats);
-
-  dest->formats = formats;
-
-  if (dest->formats)
-    gdk_content_formats_ref (dest->formats);
-
-  g_object_notify_by_pspec (G_OBJECT (dest), properties[PROP_FORMATS]);
-}
-
-/**
- * gtk_drop_target_get_formats:
- * @dest: a #GtkDropTarget
- *
- * Gets the data formats that this drop target accepts.
- *
- * If the result is %NULL, all formats are expected to be supported.
- *
- * Returns: (nullable): the supported data formats
- */
-GdkContentFormats *
-gtk_drop_target_get_formats (GtkDropTarget *dest)
-{
-  g_return_val_if_fail (GTK_IS_DROP_TARGET (dest), NULL);
-  
-  return dest->formats;
-}
-
-/**
- * gtk_drop_target_set_actions:
- * @dest: a #GtkDropTarget
- * @actions: the supported actions
- *
- * Sets the actions that this drop target supports.
- */
-void
-gtk_drop_target_set_actions (GtkDropTarget *dest,
-                             GdkDragAction  actions)
-{
-  g_return_if_fail (GTK_IS_DROP_TARGET (dest));
-  
-  if (dest->actions == actions)
-    return;
-
-  dest->actions = actions;
-
-  g_object_notify_by_pspec (G_OBJECT (dest), properties[PROP_ACTIONS]);
-}
-
-/**
- * gtk_drop_target_get_actions:
- * @dest: a #GtkDropTarget
- *
- * Gets the actions that this drop target supports.
- *
- * Returns: the actions that this drop target supports
- */
-GdkDragAction
-gtk_drop_target_get_actions (GtkDropTarget *dest)
-{
-  g_return_val_if_fail (GTK_IS_DROP_TARGET (dest), 0);
-
-  return dest->actions;
-}
-
-/**
- * gtk_drop_target_get_drop:
- * @dest: a #GtkDropTarget
- *
- * Returns the underlying #GtkDrop object for an ongoing drag.
- *
- * Returns: (nullable) (transfer none): the #GtkDrop of the current drag operation, or %NULL
- */
-GdkDrop *
-gtk_drop_target_get_drop (GtkDropTarget *dest)
-{
-  g_return_val_if_fail (GTK_IS_DROP_TARGET (dest), NULL);
-
-  return dest->drop;
-}
-
-static const char *
-gtk_drop_target_match (GtkDropTarget *dest,
-                       GdkDrop       *drop)
-{
-  GdkContentFormats *formats;
-  const char *match;
-
-  formats = gdk_content_formats_ref (dest->formats);
-  formats = gdk_content_formats_union_deserialize_mime_types (formats);
-
-  match = gdk_content_formats_match_mime_type (formats, gdk_drop_get_formats (drop));
-
-  gdk_content_formats_unref (formats);
-
-  return match;
-}
-
-/**
- * gtk_drop_target_find_mimetype:
- * @dest: a #GtkDropTarget
- *
- * Returns a mimetype that is supported both by @dest and the ongoing
- * drag. For more detailed control, you can use gdk_drop_get_formats()
- * to obtain the content formats that are supported by the source.
- *
- * Returns: (nullable): a matching mimetype for the ongoing drag, or %NULL
- */
-const char *
-gtk_drop_target_find_mimetype (GtkDropTarget *dest)
-{
-  if (!dest->drop)
-    return NULL;
-
-  if (dest->formats == NULL)
-    return NULL;
-
-  return gtk_drop_target_match (dest, dest->drop);
-}
-
-static gboolean
-gtk_drop_target_accept (GtkDropTarget *dest,
-                        GdkDrop       *drop)
-{
-  if ((gdk_drop_get_actions (drop) & gtk_drop_target_get_actions (dest)) == 0)
-    return FALSE;
-
-  if (dest->formats == NULL)
-    return TRUE;
-
-  return gdk_content_formats_match (dest->formats, gdk_drop_get_formats (drop));
-}
-
-static void
-set_drop (GtkDropTarget *dest,
-          GdkDrop       *drop)
-{
-  if (dest->drop == drop)
-    return;
-
-  if (dest->drop)
-    g_object_remove_weak_pointer (G_OBJECT (dest->drop), (gpointer *)&dest->drop);
-
-  dest->drop = drop;
-
-  if (dest->drop)
-    g_object_add_weak_pointer (G_OBJECT (dest->drop), (gpointer *)&dest->drop);
-}
-
-static void
-gtk_drop_target_emit_drag_enter (GtkDropTarget    *dest,
-                                 GdkDrop          *drop)
-{
-  set_drop (dest, drop);
-  g_signal_emit (dest, signals[DRAG_ENTER], 0, drop);
-}
-
-static void
-gtk_drop_target_emit_drag_leave (GtkDropTarget    *dest,
-                                 GdkDrop          *drop)
-{
-  set_drop (dest, drop);
-  g_signal_emit (dest, signals[DRAG_LEAVE], 0, drop);
-  set_drop (dest, NULL);
-}
-
-static gboolean
-gtk_drop_target_emit_accept (GtkDropTarget *dest,
-                             GdkDrop       *drop)
-{
-  gboolean result = FALSE;
-
-  set_drop (dest, drop);
-  g_signal_emit (dest, signals[ACCEPT], 0, drop, &result);
-
-  return result;
-}
-
-static void
-gtk_drop_target_emit_drag_motion (GtkDropTarget *dest,
-                                  GdkDrop       *drop,
-                                  int            x,
-                                  int            y)
-{
-  set_drop (dest, drop);
-  g_signal_emit (dest, signals[DRAG_MOTION], 0, drop, x, y);
-}
-
-static gboolean
-gtk_drop_target_emit_drag_drop (GtkDropTarget    *dest,
-                                GdkDrop          *drop,
-                                int               x,
-                                int               y)
-{
-  gboolean result = FALSE;
-
-  set_drop (dest, drop);
-  g_signal_emit (dest, signals[DRAG_DROP], 0, drop, x, y, &result);
-
-  return result;
-}
-
-static void
-gtk_drop_target_set_contains (GtkDropTarget *dest,
-                              gboolean       contains)
-{
-  if (dest->contains == contains)
-    return;
-
-  dest->contains = contains;
-
-  g_object_notify_by_pspec (G_OBJECT (dest), properties[PROP_CONTAINS]);
-}
-
-static gboolean
-gtk_drop_target_get_contains (GtkDropTarget *dest)
-{
-  return dest->contains;
-}
-
-static gboolean
-gtk_drop_target_filter_event (GtkEventController *controller,
-                              GdkEvent           *event)
-{
-  switch ((int)gdk_event_get_event_type (event))
-    {
-    case GDK_DRAG_ENTER:
-    case GDK_DRAG_LEAVE:
-    case GDK_DRAG_MOTION:
-    case GDK_DROP_START:
-      return GTK_EVENT_CONTROLLER_CLASS (gtk_drop_target_parent_class)->filter_event (controller, event);
-
-    default:;
-    }
-
-  return TRUE;
-}
-
-static void
-clear_current_dest (gpointer data, GObject *former_object)
-{
-  g_object_set_data (G_OBJECT (data), "current-dest", NULL);
-}
-
-static void
-unset_current_dest (gpointer data)
-{
-  GtkDropTarget *dest = data;
-  GtkWidget *widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (dest));
-
-  gtk_drop_target_set_contains (dest, FALSE);
-  if (widget)
-    gtk_widget_unset_state_flags (widget, GTK_STATE_FLAG_DROP_ACTIVE);
-}
-
-static GtkDropTarget *
-gtk_drop_get_current_dest (GdkDrop *drop)
-{
-  return GTK_DROP_TARGET (g_object_get_data (G_OBJECT (drop), "current-dest"));
-}
-
-static void
-gtk_drop_set_current_dest (GdkDrop       *drop,
-                           GtkDropTarget *dest)
-{
-  GtkDropTarget *old_dest;
-  GtkWidget *widget;
-
-  old_dest = g_object_get_data (G_OBJECT (drop), "current-dest");
-
-  if (old_dest == dest)
-    return;
-
-  if (old_dest)
-    {
-      gtk_drop_target_set_contains (old_dest, FALSE);
-
-      widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (old_dest));
-      if (widget)
-        gtk_widget_unset_state_flags (widget, GTK_STATE_FLAG_DROP_ACTIVE);
-
-      gtk_drop_target_emit_drag_leave (old_dest, drop);
-
-      g_object_weak_unref (G_OBJECT (old_dest), clear_current_dest, drop);
-    }
-
-  g_object_set_data_full (G_OBJECT (drop), "current-dest", dest, unset_current_dest);
-
-  if (dest)
-    {
-      g_object_weak_ref (G_OBJECT (dest), clear_current_dest, drop);
-
-      gtk_drop_target_emit_drag_enter (dest, drop);
-
-      widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (dest));
-      if (widget)
-        gtk_widget_set_state_flags (widget, GTK_STATE_FLAG_DROP_ACTIVE, FALSE);
-
-      gtk_drop_target_set_contains (dest, TRUE);
-    }
-}
-
-static gboolean
-gtk_drop_target_handle_event (GtkEventController *controller,
-                              GdkEvent           *event,
-                              double              x,
-                              double              y)
-{
-  GtkDropTarget *dest = GTK_DROP_TARGET (controller);
-  GdkDrop *drop;
-  GtkDropStatus status;
-  gboolean found = FALSE;
-
-  drop = gdk_drag_event_get_drop (event);
-
-  status = gtk_drop_target_get_drop_status (dest, drop);
-  if (status == GTK_DROP_STATUS_DENIED)
-    return FALSE;
-
-  switch ((int)gdk_event_get_event_type (event))
-    {
-    case GDK_DRAG_MOTION:
-      if (status != GTK_DROP_STATUS_ACCEPTED)
-        {
-          found = gtk_drop_target_emit_accept (dest, drop);
-          if (found)
-            gtk_drop_target_set_drop_status (dest, drop, GTK_DROP_STATUS_ACCEPTED);
-        }
-      else
-        found = TRUE;
-
-      if (found)
-        {
-          gdk_drop_status (drop, gtk_drop_target_get_actions (dest));
-          gtk_drop_set_current_dest (drop, dest);
-          gtk_drop_target_emit_drag_motion (dest, drop, x, y);
-        }
-      break;
-
-    case GDK_DROP_START:
-      found = gtk_drop_target_emit_drag_drop (dest, drop, x, y);
-      break;
-
-    default:
-      break;
-    }
-
-  return found;
-}
-
-/*
- * This function is called if none of the event
- * controllers has handled a drag event.
- */
-void
-gtk_drag_dest_handle_event (GtkWidget *toplevel,
-                            GdkEvent  *event)
-{
-  GdkDrop *drop;
-  GdkEventType event_type;
-
-  g_return_if_fail (toplevel != NULL);
-  g_return_if_fail (event != NULL);
-
-  event_type = gdk_event_get_event_type (event);
-  drop = gdk_drag_event_get_drop (event);
-
-  switch ((guint) event_type)
-    {
-    case GDK_DRAG_LEAVE:
-      gtk_drop_set_current_dest (drop, NULL);
-      break;
-
-    case GDK_DRAG_ENTER:
-    case GDK_DRAG_MOTION:
-    case GDK_DROP_START:
-      gtk_drop_set_current_dest (drop, NULL);
-      gdk_drop_status (drop, 0);
-      break;
-
-    default:
-      g_assert_not_reached ();
-    }
-}
-
-static GtkDropStatus
-gtk_drop_target_get_drop_status (GtkDropTarget *dest,
-                                 GdkDrop       *drop)
-{
-  GHashTable *denied;
-
-  denied = (GHashTable *)g_object_get_data (G_OBJECT (drop), "denied-drags");
-  if (denied)
-    return GPOINTER_TO_INT (g_hash_table_lookup (denied, dest));
-
-  return GTK_DROP_STATUS_NONE;
-}
-
-static void
-gtk_drop_target_set_drop_status (GtkDropTarget *dest,
-                                 GdkDrop       *drop,
-                                 GtkDropStatus  status)
-{
-  GHashTable *drags;
-
-  drags = (GHashTable *)g_object_get_data (G_OBJECT (drop), "denied-drags");
-  if (!drags)
-    {
-      drags = g_hash_table_new (NULL, NULL);
-      g_object_set_data_full (G_OBJECT (drop), "denied-drags", drags, (GDestroyNotify)g_hash_table_unref);
-    }
-
-  g_hash_table_insert (drags, dest, GINT_TO_POINTER (status));
-
-  if (dest == gtk_drop_get_current_dest (drop))
-    {
-      gdk_drop_status (drop, 0);
-      gtk_drop_set_current_dest (drop, NULL);
-    }
-}
-
-/**
- * gtk_drop_target_deny_drop:
- * @dest: a #GtkDropTarget
- * @drop: the #GdkDrop of an ongoing drag operation
- *
- * Sets the @drop as not accepted on this drag site.
- *
- * This function should be used when delaying the decision
- * on whether to accept a drag or not until after reading
- * the data.
- */
-void
-gtk_drop_target_deny_drop (GtkDropTarget *dest,
-                           GdkDrop       *drop)
-{
-  g_return_if_fail (GTK_IS_DROP_TARGET (dest));
-  g_return_if_fail (GDK_IS_DROP (drop));
-
-  gtk_drop_target_set_drop_status (dest, drop, GTK_DROP_STATUS_DENIED);
-}
diff --git a/gtk/gtkdragdest.h b/gtk/gtkdragdest.h
deleted file mode 100644 (file)
index 6ebec76..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-/* -*- Mode: C; c-file-style: "gnu"; tab-width: 8 -*- */
-/* GTK - The GIMP Toolkit
- * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/*
- * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
- * file for a list of people on the GTK+ Team.  See the ChangeLog
- * files for a list of changes.  These files are distributed with
- * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
- */
-
-#ifndef __GTK_DRAG_DEST_H__
-#define __GTK_DRAG_DEST_H__
-
-
-#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
-#error "Only <gtk/gtk.h> can be included directly."
-#endif
-
-#include <gtk/gtkwidget.h>
-
-
-G_BEGIN_DECLS
-
-typedef struct _GtkDropTarget GtkDropTarget;
-
-
-#define GTK_TYPE_DROP_TARGET         (gtk_drop_target_get_type ())
-#define GTK_DROP_TARGET(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GTK_TYPE_DROP_TARGET, GtkDropTarget))
-#define GTK_DROP_TARGET_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST ((k), GTK_TYPE_DROP_TARGET, GtkDropTargetClass))
-#define GTK_IS_DROP_TARGET(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTK_TYPE_DROP_TARGET))
-#define GTK_IS_DROP_TARGET_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), GTK_TYPE_DROP_TARGET))
-#define GTK_DROP_TARGET_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GTK_TYPE_DROP_TARGET, GtkDropTargetClass))
-
-typedef struct _GtkDropTargetClass GtkDropTargetClass;
-
-GDK_AVAILABLE_IN_ALL
-GType              gtk_drop_target_get_type         (void) G_GNUC_CONST;
-
-GDK_AVAILABLE_IN_ALL
-GtkDropTarget       *gtk_drop_target_new            (GdkContentFormats *formats,
-                                                     GdkDragAction      actions);
-
-GDK_AVAILABLE_IN_ALL
-void               gtk_drop_target_set_formats      (GtkDropTarget     *dest,
-                                                     GdkContentFormats *formats);
-GDK_AVAILABLE_IN_ALL
-GdkContentFormats *gtk_drop_target_get_formats      (GtkDropTarget     *dest);
-
-GDK_AVAILABLE_IN_ALL
-void               gtk_drop_target_set_actions      (GtkDropTarget     *dest,
-                                                     GdkDragAction      actions);
-GDK_AVAILABLE_IN_ALL
-GdkDragAction      gtk_drop_target_get_actions      (GtkDropTarget     *dest);
-
-GDK_AVAILABLE_IN_ALL
-GdkDrop           *gtk_drop_target_get_drop         (GtkDropTarget     *dest);
-
-GDK_AVAILABLE_IN_ALL
-const char        *gtk_drop_target_find_mimetype    (GtkDropTarget     *dest);
-
-GDK_AVAILABLE_IN_ALL
-void                gtk_drop_target_deny_drop      (GtkDropTarget       *dest,
-                                                    GdkDrop             *drop);
-
-
-G_END_DECLS
-
-#endif /* __GTK_DRAG_DEST_H__ */
diff --git a/gtk/gtkdrop.c b/gtk/gtkdrop.c
new file mode 100644 (file)
index 0000000..7c4c834
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * Copyright Â© 2020 Benjamin Otte
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Benjamin Otte <otte@gnome.org>
+ */
+
+#include "config.h"
+
+#include "gtkdropprivate.h"
+
+typedef struct _GtkDrop GtkDrop;
+
+struct _GtkDrop
+{
+  /* TRUE if we are waiting for a gdk_drop_status() call */
+  gboolean waiting;
+  /* TRUE if begin_event() has been called but end_event() hasn't yet - purely for debugging */
+  gboolean active;
+};
+
+static void
+gtk_drop_free (gpointer data)
+{
+  GtkDrop *self = data;
+
+  g_slice_free (GtkDrop, self);
+}
+
+static GtkDrop *
+gtk_drop_lookup (GdkDrop *drop)
+{
+  static GQuark drop_quark = 0;
+  GtkDrop *result;
+
+  if (G_UNLIKELY (drop_quark == 0))
+    drop_quark = g_quark_from_string ("-gtk-drop-data");
+
+  result = g_object_get_qdata (G_OBJECT (drop), drop_quark);
+  if (result == NULL)
+    {
+      result = g_slice_new0 (GtkDrop);
+      g_object_set_qdata_full (G_OBJECT (drop), drop_quark, result, gtk_drop_free);
+    }
+
+  return result;
+}
+
+void
+gtk_drop_begin_event (GdkDrop      *drop,
+                      GdkEventType  event_type)
+{
+  GtkDrop *self;
+
+  self = gtk_drop_lookup (drop);
+
+  g_assert (self->waiting == FALSE);
+  g_assert (self->active == FALSE);
+
+  self->active = TRUE;
+  if (event_type == GDK_DRAG_ENTER ||
+      event_type == GDK_DRAG_MOTION)
+    self->waiting = TRUE;
+}
+
+void
+gtk_drop_end_event (GdkDrop *drop)
+{
+  GtkDrop *self;
+
+  self = gtk_drop_lookup (drop);
+
+  g_assert (self->active == TRUE);
+
+  if (self->waiting)
+    {
+      gdk_drop_status (drop, 0);
+      self->waiting = FALSE;
+    }
+  self->active = FALSE;
+}
+
+gboolean
+gtk_drop_status (GdkDrop       *drop,
+                 GdkDragAction  actions,
+                 GdkDragAction  preferred_action)
+{
+  GtkDrop *self;
+
+  self = gtk_drop_lookup (drop);
+
+  g_assert (self->active == TRUE);
+
+  if (!self->waiting)
+    return FALSE;
+
+  gdk_drop_status (drop, actions);
+  self->waiting = FALSE;
+  return TRUE;
+}
+                     
diff --git a/gtk/gtkdropprivate.h b/gtk/gtkdropprivate.h
new file mode 100644 (file)
index 0000000..769013b
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright Â© 2020 Benjamin Otte
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Benjamin Otte <otte@gnome.org>
+ */
+
+#ifndef __GTK_DROP_PRIVATE_H__
+#define __GTK_DROP_PRIVATE_H__
+
+#include <gdk/gdk.h>
+
+G_BEGIN_DECLS
+
+
+void                    gtk_drop_begin_event                    (GdkDrop                *drop,
+                                                                 GdkEventType            event_type);
+void                    gtk_drop_end_event                      (GdkDrop                *drop);
+
+gboolean                gtk_drop_status                         (GdkDrop                *drop,
+                                                                 GdkDragAction           actions,
+                                                                 GdkDragAction           preferred_action);
+
+G_END_DECLS
+
+#endif
diff --git a/gtk/gtkdroptarget.c b/gtk/gtkdroptarget.c
new file mode 100644 (file)
index 0000000..3bd86fa
--- /dev/null
@@ -0,0 +1,990 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 1995-1999 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#include "config.h"
+
+#include "gtkdroptarget.h"
+
+#include "gtkdropprivate.h"
+#include "gtkeventcontrollerprivate.h"
+#include "gtkintl.h"
+#include "gtkmarshalers.h"
+#include "gtknative.h"
+#include "gtkprivate.h"
+#include "gtktypebuiltins.h"
+
+
+/**
+ * SECTION:gtkdroptarget
+ * @Short_description: Event controller to receive DND drops
+ * @Title: GtkDropTarget
+ * @See_also: #GdkDrop, #GtkDropTargetAsync
+ *
+ * GtkDropTarget is an event controller implementing a simple way to
+ * receive Drag-and-Drop operations.
+ *
+ * The most basic way to use a #GtkDropTarget to receive drops on a
+ * widget, is to create it via gtk_drop_target_new(), passing in the
+ * #GType of the data you want to receive and connect to the
+ * GtkDropTarget::drop signal to receive the data.
+ *
+ * #GtkDropTarget supports more options, such as:
+ *
+ *  * rejecting potential drops via the GtkDropTarget::accept signal
+ *    and the gtk_drop_target_reject() function to let other drop
+ *    targets handle the drop
+ *  * tracking an ongoing drag operation before the drop via the
+ *    GtkDropTarget::enter, GtkDropTarget::motion and
+ *    GtkDropTarget::leave signals
+ *  * configuring how to receive data by setting the
+ *    GtkDropTarget:preload property and listening for its availability
+ *    via the GtkDropTarget:value property
+ *
+ * However, #GtkDropTarget is ultimately modeled in a synchronous way
+ * and only supports data transferred via #GType.  
+ * If you want full control over an ongoing drop, the #GdkDropTargetAsync
+ * object gives you this ability.
+ *
+ * While a pointer is dragged over the drop target's widget and the drop
+ * has not been rejected, that widget will receive the
+ * %GTK_STATE_FLAG_DROP_ACTIVE state, which can be used to style the widget.
+ */
+
+struct _GtkDropTarget
+{
+  GtkEventController parent_object;
+
+  GdkContentFormats *formats;
+  GdkDragAction actions;
+  guint preload : 1;
+
+  guint dropping : 1;
+  graphene_point_t coords;
+  GdkDrop *drop;
+  GCancellable *cancellable; /* NULL unless doing a read of value */
+  GValue value;
+};
+
+struct _GtkDropTargetClass
+{
+  GtkEventControllerClass parent_class;
+
+  gboolean              (* accept)                              (GtkDropTarget  *self,
+                                                                 GdkDrop        *drop);
+  GdkDragAction         (* enter)                               (GtkDropTarget  *self,
+                                                                 double          x,
+                                                                 double          y);
+  GdkDragAction         (* motion)                              (GtkDropTarget  *self,
+                                                                 double          x,
+                                                                 double          y);
+  void                  (* leave)                               (GtkDropTarget  *self,
+                                                                 GdkDrop        *drop);
+  gboolean              (* drop)                                (GtkDropTarget  *self,
+                                                                 const GValue   *value,
+                                                                 double          x,
+                                                                 double          y);
+};
+
+enum {
+  PROP_0,
+  PROP_ACTIONS,
+  PROP_DROP,
+  PROP_FORMATS,
+  PROP_PRELOAD,
+  PROP_VALUE,
+  NUM_PROPERTIES
+};
+
+static GParamSpec *properties[NUM_PROPERTIES];
+
+enum {
+  ACCEPT,
+  ENTER,
+  MOTION,
+  LEAVE,
+  DROP,
+  NUM_SIGNALS
+};
+
+static guint signals[NUM_SIGNALS];
+
+G_DEFINE_TYPE (GtkDropTarget, gtk_drop_target, GTK_TYPE_EVENT_CONTROLLER);
+
+static void
+gtk_drop_target_end_drop (GtkDropTarget *self)
+{
+  if (self->drop == NULL)
+    return;
+
+  g_object_freeze_notify (G_OBJECT (self));
+
+  if (self->dropping)
+    {
+      gdk_drop_finish (self->drop, 0);
+      self->dropping = FALSE;
+    }
+
+  g_clear_object (&self->drop);
+  g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DROP]);
+
+  if (G_IS_VALUE (&self->value))
+    {
+      g_value_unset (&self->value);
+      g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_VALUE]);
+    }
+
+  if (self->cancellable)
+    {
+      g_cancellable_cancel (self->cancellable);
+      g_clear_object (&self->cancellable);
+    }
+
+  gtk_widget_unset_state_flags (gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (self)),
+                                GTK_STATE_FLAG_DROP_ACTIVE);
+
+  g_object_thaw_notify (G_OBJECT (self));
+}
+
+static void
+gtk_drop_target_do_drop (GtkDropTarget *self)
+{
+  gboolean success;
+
+  g_assert (self->dropping);
+  g_assert (G_IS_VALUE (&self->value));
+
+  g_signal_emit (self, signals[DROP], 0, &self->value, self->coords.x, self->coords.y, &success);
+
+  if (success)
+    gdk_drop_finish (self->drop, gdk_drop_get_actions (self->drop));
+  else
+    gdk_drop_finish (self->drop, 0);
+
+  self->dropping = FALSE;
+
+  gtk_drop_target_end_drop (self);
+}
+
+static void
+gtk_drop_target_load_done (GObject      *source,
+                           GAsyncResult *res,
+                           gpointer      data)
+{
+  GtkDropTarget *self = data;
+  const GValue *value;
+  GError *error = NULL;
+
+  value = gdk_drop_read_value_finish (GDK_DROP (source), res, &error);
+  if (value == NULL)
+    {
+      /* If this happens, data/self is invalid */
+      if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+        {
+          g_clear_error (&error);
+          return;
+        }
+
+      g_clear_object (&self->cancellable);
+      /* XXX: Should this be a warning? */
+      g_warning ("Failed to receive drop data: %s", error->message);
+      g_clear_error (&error);
+      gtk_drop_target_end_drop (self);
+      return;
+    }
+
+  g_clear_object (&self->cancellable);
+  g_value_init (&self->value, G_VALUE_TYPE (value));
+  g_value_copy (value, &self->value);
+  g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_VALUE]);
+
+  if (self->dropping)
+    gtk_drop_target_do_drop (self);
+}
+
+static gboolean
+gtk_drop_target_load (GtkDropTarget *self)
+{
+  g_assert (self->drop);
+
+  if (G_IS_VALUE (&self->value))
+    return TRUE;
+
+  if (self->cancellable)
+    return FALSE;
+
+  self->cancellable = g_cancellable_new ();
+
+  gdk_drop_read_value_async (self->drop, 
+                             gdk_content_formats_match_gtype (self->formats, gdk_drop_get_formats (self->drop)),
+                             G_PRIORITY_DEFAULT,
+                             self->cancellable,
+                             gtk_drop_target_load_done,
+                             g_object_ref (self));
+  return FALSE;
+}
+
+static void
+gtk_drop_target_start_drop (GtkDropTarget *self,
+                            GdkDrop       *drop)
+{
+  g_object_freeze_notify (G_OBJECT (self));
+
+  gtk_drop_target_end_drop (self);
+
+  self->drop = g_object_ref (drop);
+  g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DROP]);
+
+  if (self->preload)
+    gtk_drop_target_load (self);
+
+  gtk_widget_set_state_flags (gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (self)),
+                              GTK_STATE_FLAG_DROP_ACTIVE,
+                              FALSE);
+
+  g_object_thaw_notify (G_OBJECT (self));
+}
+
+static gboolean
+gtk_drop_target_accept (GtkDropTarget *self,
+                        GdkDrop       *drop)
+{
+  if ((gdk_drop_get_actions (drop) & gtk_drop_target_get_actions (self)) == 0)
+    return FALSE;
+
+  if (self->formats == NULL)
+    return TRUE;
+
+  return gdk_content_formats_match (self->formats, gdk_drop_get_formats (drop));
+}
+
+static GdkDragAction
+make_action_unique (GdkDragAction actions)
+{
+  if (actions & GDK_ACTION_COPY)
+    return GDK_ACTION_COPY;
+
+  if (actions & GDK_ACTION_MOVE)
+    return GDK_ACTION_MOVE;
+  
+  if (actions & GDK_ACTION_LINK)
+    return GDK_ACTION_LINK;
+
+  return 0;
+}
+  
+static GdkDragAction
+gtk_drop_target_enter (GtkDropTarget  *self,
+                       double          x,
+                       double          y)
+{
+  return make_action_unique (self->actions & gdk_drop_get_actions (self->drop));
+}
+
+static GdkDragAction         
+gtk_drop_target_motion (GtkDropTarget  *self,
+                        double          x,
+                        double          y)
+{
+  return make_action_unique (self->actions & gdk_drop_get_actions (self->drop));
+}
+
+static gboolean
+gtk_drop_target_drop (GtkDropTarget  *self,
+                      const GValue   *value,
+                      double          x,
+                      double          y)
+{
+  return FALSE;
+}
+
+static gboolean
+gtk_drop_target_filter_event (GtkEventController *controller,
+                              GdkEvent           *event)
+{
+  switch ((int) gdk_event_get_event_type (event))
+    {
+    case GDK_DRAG_ENTER:
+    case GDK_DRAG_LEAVE:
+    case GDK_DRAG_MOTION:
+    case GDK_DROP_START:
+      return GTK_EVENT_CONTROLLER_CLASS (gtk_drop_target_parent_class)->filter_event (controller, event);
+
+    default:;
+    }
+
+  return TRUE;
+}
+
+static gboolean
+gtk_drop_target_handle_event (GtkEventController *controller,
+                              GdkEvent           *event,
+                              double              x,
+                              double              y)
+{
+  GtkDropTarget *self = GTK_DROP_TARGET (controller);
+
+  /* All drops have been rejected. New drops only arrive via crossing
+   * events, so we can: */
+  if (self->drop == NULL)
+    return FALSE;
+
+  switch ((int) gdk_event_get_event_type (event))
+    {
+    case GDK_DRAG_MOTION:
+      {
+        GtkWidget *widget = gtk_event_controller_get_widget (controller);
+        GdkDragAction preferred;
+
+        /* sanity check */
+        g_return_val_if_fail (self->drop == gdk_drag_event_get_drop (event), FALSE);
+
+        graphene_point_init (&self->coords, x, y);
+        g_signal_emit (self, signals[MOTION], 0, x, y, &preferred);
+        if (preferred &&
+            gtk_drop_status (self->drop, self->actions, preferred))
+          {
+            gtk_widget_set_state_flags (widget, GTK_STATE_FLAG_DROP_ACTIVE, FALSE);
+          }
+        else
+          {
+            gtk_widget_unset_state_flags (widget, GTK_STATE_FLAG_DROP_ACTIVE);
+          }
+      }
+      return FALSE;
+
+    case GDK_DROP_START:
+      {
+        /* sanity check */
+        g_return_val_if_fail (self->drop == gdk_drag_event_get_drop (event), FALSE);
+
+        graphene_point_init (&self->coords, x, y);
+        self->dropping = TRUE;
+        if (gtk_drop_target_load (self))
+          gtk_drop_target_do_drop (self);
+
+        return TRUE;
+      }
+
+    default:
+      return FALSE;
+    }
+}
+
+static void
+gtk_drop_target_handle_crossing (GtkEventController    *controller,
+                                 const GtkCrossingData *crossing,
+                                 double                 x,
+                                 double                 y)
+{
+  GtkDropTarget *self = GTK_DROP_TARGET (controller);
+  GtkWidget *widget = gtk_event_controller_get_widget (controller);
+
+  if (crossing->type != GTK_CROSSING_DROP)
+    return;
+
+  /* sanity check */
+  g_warn_if_fail (self->drop == NULL || self->drop == crossing->drop);
+
+  if (crossing->direction == GTK_CROSSING_IN)
+    {
+      gboolean accept = FALSE;
+      GdkDragAction preferred;
+
+      if (self->drop != NULL)
+        return;
+
+      /* if we were a target already but self->drop == NULL, the drop
+       * was rejected already */
+      if (crossing->old_descendent != NULL ||
+          crossing->old_target == widget)
+        return;
+
+      g_signal_emit (self, signals[ACCEPT], 0, crossing->drop, &accept);
+      if (!accept)
+        return;
+
+      graphene_point_init (&self->coords, x, y);
+      gtk_drop_target_start_drop (self, crossing->drop);
+
+      g_signal_emit (self, signals[ENTER], 0, x, y, &preferred);
+      if (preferred &&
+          gtk_drop_status (self->drop, self->actions, preferred))
+        {
+          gtk_widget_set_state_flags (widget, GTK_STATE_FLAG_DROP_ACTIVE, FALSE);
+        }
+      else
+        {
+          gtk_widget_unset_state_flags (widget, GTK_STATE_FLAG_DROP_ACTIVE);
+        }
+    }
+  else
+    {
+      if (crossing->new_descendent != NULL ||
+          crossing->new_target == widget)
+        return;
+
+      g_signal_emit (self, signals[LEAVE], 0, self->drop);
+      if (!self->dropping)
+        gtk_drop_target_end_drop (self);
+      gtk_widget_unset_state_flags (widget, GTK_STATE_FLAG_DROP_ACTIVE);
+    }
+}
+
+static void
+gtk_drop_target_finalize (GObject *object)
+{
+  GtkDropTarget *self = GTK_DROP_TARGET (object);
+
+  g_clear_pointer (&self->formats, gdk_content_formats_unref);
+
+  G_OBJECT_CLASS (gtk_drop_target_parent_class)->finalize (object);
+}
+
+static void
+gtk_drop_target_set_property (GObject      *object,
+                              guint         prop_id,
+                              const GValue *value,
+                              GParamSpec   *pspec)
+{
+  GtkDropTarget *self = GTK_DROP_TARGET (object);
+
+  switch (prop_id)
+    {
+    case PROP_ACTIONS:
+      gtk_drop_target_set_actions (self, g_value_get_flags (value));
+      break;
+
+    case PROP_PRELOAD:
+      gtk_drop_target_set_preload (self, g_value_get_boolean (value));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gtk_drop_target_get_property (GObject    *object,
+                              guint       prop_id,
+                              GValue     *value,
+                              GParamSpec *pspec)
+{
+  GtkDropTarget *self = GTK_DROP_TARGET (object);
+
+  switch (prop_id)
+    {
+    case PROP_ACTIONS:
+      g_value_set_flags (value, self->actions);
+      break;
+
+    case PROP_DROP:
+      g_value_set_object (value, self->drop);
+      break;
+
+    case PROP_FORMATS:
+      g_value_set_boxed (value, self->formats);
+      break;
+
+    case PROP_PRELOAD:
+      g_value_set_boolean (value, self->preload);
+      break;
+
+    case PROP_VALUE:
+      if (G_IS_VALUE (&self->value))
+        g_value_set_boxed (value, &self->value);
+      else
+        g_value_set_boxed (value, NULL);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gtk_drop_target_class_init (GtkDropTargetClass *class)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (class);
+  GtkEventControllerClass *controller_class = GTK_EVENT_CONTROLLER_CLASS (class);
+
+  object_class->finalize = gtk_drop_target_finalize;
+  object_class->set_property = gtk_drop_target_set_property;
+  object_class->get_property = gtk_drop_target_get_property;
+
+  controller_class->handle_event = gtk_drop_target_handle_event;
+  controller_class->filter_event = gtk_drop_target_filter_event;
+  controller_class->handle_crossing = gtk_drop_target_handle_crossing;
+
+  class->accept = gtk_drop_target_accept;
+  class->enter = gtk_drop_target_enter;
+  class->motion = gtk_drop_target_motion;
+  class->drop = gtk_drop_target_drop;
+
+  /**
+   * GtkDropTarget:actions:
+   *
+   * The #GdkDragActions that this drop target supports
+   */ 
+  properties[PROP_ACTIONS] =
+       g_param_spec_flags ("actions",
+                           P_("Actions"),
+                           P_("The actions supported by this drop target"),
+                           GDK_TYPE_DRAG_ACTION, 0,
+                           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
+
+  /**
+   * GtkDropTarget:drop:
+   *
+   * The #GdkDrop that is currently being performed
+   */
+  properties[PROP_DROP] =
+       g_param_spec_object ("drop",
+                            P_("Drop"),
+                            P_("Current drop"),
+                            GDK_TYPE_DROP,
+                            GTK_PARAM_READABLE);
+
+  /**
+   * GtkDropTarget:formats:
+   *
+   * The #GdkContentFormats that determine the supported data formats
+   */
+  properties[PROP_FORMATS] =
+       g_param_spec_boxed ("formats",
+                           P_("Formats"),
+                           P_("The supported formats"),
+                           GDK_TYPE_CONTENT_FORMATS,
+                           GTK_PARAM_READABLE);
+
+  /**
+   * GtkDropTarget:preload:
+   *
+   * Whether the drop data should be preloaded when the pointer is only
+   * hovering over the widget but has not been released.
+   *
+   * Setting this property allows finer grained reaction to an ongoing
+   * drop at the cost of loading more data.
+   *
+   * The default value for this property is %FALSE to avoid downloading
+   * huge amounts of data by accident.  
+   * For example, if somebody drags a full document of gigabytes of text
+   * from a text editor across a widget with a preloading drop target,
+   * this data will be downlaoded, even if the data is ultimately dropped
+   * elsewhere.
+   *
+   * For a lot of data formats, the amount of data is very small (like
+   * %GDK_TYPE_RGBA), so enabling this property does not hurt at all.
+   */
+  properties[PROP_PRELOAD] =
+       g_param_spec_boolean ("preload",
+                             P_("Preload"),
+                             P_("Whether drop data should be preloaded while hovering"),
+                             FALSE,
+                             G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
+
+  /**
+   * GtkDropTarget:value:
+   *
+   * The value for this drop operation or %NULL if the data has not been
+   * loaded yet or no drop operation is going on.
+   *
+   * Data may be available before the GtkDropTarget::drop signal gets emitted -
+   * for example when the GtkDropTarget:preload property is set.
+   * You can use the GObject::notify signal to be notified of available data.
+   */
+  properties[PROP_VALUE] =
+       g_param_spec_boxed ("value",
+                           P_("Value"),
+                           P_("The value for this drop operation"),
+                           G_TYPE_VALUE,
+                           GTK_PARAM_READABLE);
+
+  g_object_class_install_properties (object_class, NUM_PROPERTIES, properties);
+
+ /**
+   * GtkDropTarget::accept:
+   * @self: the #GtkDropTarget
+   * @drop: the #GdkDrop
+   *
+   * The ::accept signal is emitted on the drop site when a drop operation
+   * is about to begin.  
+   * If the drop is not accepted, %FALSE will be returned and the drop target
+   * will ignore the drop. If %TRUE is returned, the drop is accepted for now
+   * but may be rejected later via a call to gtk_drop_target_reject() or
+   * ultimately by returning %FALSE from GtkDropTarget::drop
+   *
+   * The default handler for this signal decides whether to accept the drop
+   * based on the formats provided by the @drop.
+   *
+   * If the decision whether the drop will be accepted or rejected needs
+   * inspecting the data, this function should return %TRUE, the 
+   * GtkDropTarget:preload property should be set and the value
+   * should be inspected via the GObject::notify:value signal and then call
+   * gtk_drop_target_reject().
+   *
+   * Returns: %TRUE if @drop is accepted
+   */
+  signals[ACCEPT] =
+      g_signal_new (I_("accept"),
+                    G_TYPE_FROM_CLASS (class),
+                    G_SIGNAL_RUN_LAST,
+                    G_STRUCT_OFFSET (GtkDropTargetClass, accept),
+                    g_signal_accumulator_first_wins, NULL,
+                    NULL,
+                    G_TYPE_BOOLEAN, 1,
+                    GDK_TYPE_DROP);
+
+  /**
+   * GtkDropTarget::enter:
+   * @self: the #GtkDropTarget
+   * @x: the x coordinate of the current pointer position
+   * @y: the y coordinate of the current pointer position
+   *
+   * The ::enter signal is emitted on the drop site when the pointer
+   * enters the widget. It can be used to set up custom highlighting.
+   *
+   * Returns: Preferred action for this drag operation or 0 if dropping is not
+   *     supported at the current @x,@y location.
+   */
+  signals[ENTER] =
+      g_signal_new (I_("enter"),
+                    G_TYPE_FROM_CLASS (class),
+                    G_SIGNAL_RUN_LAST,
+                    G_STRUCT_OFFSET (GtkDropTargetClass, enter),
+                    g_signal_accumulator_first_wins, NULL,
+                    NULL,
+                    GDK_TYPE_DRAG_ACTION, 2,
+                    G_TYPE_DOUBLE, G_TYPE_DOUBLE);
+
+  /**
+   * GtkDropTarget::motion:
+   * @self: the #GtkDropTarget
+   * @x: the x coordinate of the current pointer position
+   * @y: the y coordinate of the current pointer position
+   *
+   * The ::motion signal is emitted while the pointer is moving
+   * over the drop target.
+   *
+   * Returns: Preferred action for this drag operation or 0 if dropping is not
+   *     supported at the current @x,@y location.
+   */
+  signals[MOTION] =
+      g_signal_new (I_("motion"),
+                    G_TYPE_FROM_CLASS (class),
+                    G_SIGNAL_RUN_LAST,
+                    G_STRUCT_OFFSET (GtkDropTargetClass, motion),
+                    g_signal_accumulator_first_wins, NULL,
+                    NULL,
+                    GDK_TYPE_DRAG_ACTION, 2,
+                    G_TYPE_DOUBLE, G_TYPE_DOUBLE);
+
+  /**
+   * GtkDropTarget::leave:
+   * @self: the #GtkDropTarget
+   * @drop: the #GdkDrop
+   *
+   * The ::leave signal is emitted on the drop site when the pointer
+   * leaves the widget. Its main purpose it to undo things done in
+   * #GtkDropTarget::enter.
+   */
+  signals[LEAVE] =
+      g_signal_new (I_("leave"),
+                    G_TYPE_FROM_CLASS (class),
+                    G_SIGNAL_RUN_LAST,
+                    G_STRUCT_OFFSET (GtkDropTargetClass, leave),
+                    NULL, NULL,
+                    NULL,
+                    G_TYPE_NONE, 0);
+
+  /**
+   * GtkDropTarget::drop:
+   * @self: the #GtkDropTarget
+   * @value: the #GValue being dropped
+   * @x: the x coordinate of the current pointer position
+   * @y: the y coordinate of the current pointer position
+   *
+   * The ::drop signal is emitted on the drop site when the user drops
+   * the data onto the widget. The signal handler must determine whether
+   * the pointer position is in a drop zone or not. If it is not in a drop
+   * zone, it returns %FALSE and no further processing is necessary.
+   *
+   * Otherwise, the handler returns %TRUE. In this case, this handler will
+   * accept the drop. The handler is responsible for rading the given @value
+   * and performing the drop operation.
+   *
+   * Returns: whether the drop was accepted at the given pointer position
+   */
+  signals[DROP] =
+      g_signal_new (I_("drop"),
+                    G_TYPE_FROM_CLASS (class),
+                    G_SIGNAL_RUN_LAST,
+                    0,
+                    g_signal_accumulator_first_wins, NULL,
+                    NULL,
+                    G_TYPE_BOOLEAN, 3,
+                    G_TYPE_VALUE, G_TYPE_DOUBLE, G_TYPE_DOUBLE);
+}
+
+static void
+gtk_drop_target_init (GtkDropTarget *self)
+{
+  self->formats = gdk_content_formats_new (NULL, 0);
+}
+
+/**
+ * gtk_drop_target_new:
+ * @type: The supported type or %G_TYPE_INVALID
+ * @actions: the supported actions
+ *
+ * Creates a new #GtkDropTarget object.
+ *
+ * If the drop target should support more than 1 type, pass
+ * %G_TYPE_INVALID for @type and then call
+ * gtk_drop_target_set_gtypes().
+ *
+ * Returns: the new #GtkDropTarget
+ */
+GtkDropTarget *
+gtk_drop_target_new (GType         type,
+                     GdkDragAction actions)
+{
+  GtkDropTarget *result;
+
+  result = g_object_new (GTK_TYPE_DROP_TARGET,
+                         "actions", actions,
+                         NULL);
+
+  if (type != G_TYPE_INVALID)
+    gtk_drop_target_set_gtypes (result, &type, 1);
+
+  return result;
+}
+
+/**
+ * gtk_drop_target_get_formats:
+ * @self: a #GtkDropTarget
+ *
+ * Gets the data formats that this drop target accepts.
+ *
+ * If the result is %NULL, all formats are expected to be supported.
+ *
+ * Returns: (nullable): the supported data formats
+ */
+GdkContentFormats *
+gtk_drop_target_get_formats (GtkDropTarget *self)
+{
+  g_return_val_if_fail (GTK_IS_DROP_TARGET (self), NULL);
+  
+  return self->formats;
+}
+
+/**
+ * gtk_drop_target_set_gtypes:
+ * @self: a #GtkDropTarget
+ * @types: (nullable) (transfer none) (array length=n_types):
+ *     all supported #GTypes that can be dropped
+ * @n_types: number of @types
+ *
+ * Sets the supported #GTypes for this drop target.
+ *
+ * The GtkDropTarget::drop signal will 
+ **/
+void
+gtk_drop_target_set_gtypes (GtkDropTarget *self,
+                            GType         *types,
+                            gsize          n_types)
+{
+  GdkContentFormatsBuilder *builder;
+  gsize i;
+
+  g_return_if_fail (GTK_IS_DROP_TARGET (self));
+  g_return_if_fail (n_types == 0 || types != NULL);
+
+  gdk_content_formats_unref (self->formats);
+
+  builder = gdk_content_formats_builder_new ();
+  for (i = 0; i < n_types; i++)
+    gdk_content_formats_builder_add_gtype (builder, types[i]);
+  
+  self->formats = gdk_content_formats_builder_free_to_formats (builder);
+
+  g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FORMATS]);
+}
+
+/**
+ * gtk_drop_target_get_gtypes:
+ * @self: a #GtkDropTarget
+ * @n_gtypes: (out) (allow-none): optional pointer to take the
+ *     number of #GTypes contained in the return value
+ *
+ * Gets the list of supported #GTypes for @self. If no type have been set,
+ * %NULL will be returned.
+ *
+ * Returns: (transfer none) (nullable): %G_TYPE_INVALID-terminated array of 
+ *     types included in @formats or %NULL if none.
+ **/
+const GType *
+gtk_drop_target_get_gtypes (GtkDropTarget *self,
+                            gsize         *n_types)
+{
+  g_return_val_if_fail (GTK_IS_DROP_TARGET (self), NULL);
+
+  return gdk_content_formats_get_gtypes (self->formats, n_types);
+}
+
+/**
+ * gtk_drop_target_set_actions:
+ * @self: a #GtkDropTarget
+ * @actions: the supported actions
+ *
+ * Sets the actions that this drop target supports.
+ */
+void
+gtk_drop_target_set_actions (GtkDropTarget *self,
+                             GdkDragAction  actions)
+{
+  g_return_if_fail (GTK_IS_DROP_TARGET (self));
+  
+  if (self->actions == actions)
+    return;
+
+  self->actions = actions;
+
+  g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ACTIONS]);
+}
+
+/**
+ * gtk_drop_target_get_actions:
+ * @self: a #GtkDropTarget
+ *
+ * Gets the actions that this drop target supports.
+ *
+ * Returns: the actions that this drop target supports
+ */
+GdkDragAction
+gtk_drop_target_get_actions (GtkDropTarget *self)
+{
+  g_return_val_if_fail (GTK_IS_DROP_TARGET (self), 0);
+
+  return self->actions;
+}
+
+/**
+ * gtk_drop_target_set_preload:
+ * @self: a #GtkDropTarget
+ * @preload: %TRUE to preload drop data
+ *
+ * Sets the GtkDropTarget:preload property.
+ **/
+void
+gtk_drop_target_set_preload (GtkDropTarget *self,
+                             gboolean       preload)
+{
+  g_return_if_fail (GTK_IS_DROP_TARGET (self));
+  
+  if (self->preload == preload)
+    return;
+
+  self->preload = preload;
+
+  g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_PRELOAD]);
+}
+
+/**
+ * gtk_drop_target_get_preload:
+ * @self: a #GtkDropTarget
+ *
+ * Gets the value of the GtkDropTarget:preload property.
+ *
+ * Returns: %TRUE if drop data should be preloaded
+ */
+gboolean
+gtk_drop_target_get_preload (GtkDropTarget *self)
+{
+  g_return_val_if_fail (GTK_IS_DROP_TARGET (self), 0);
+
+  return self->preload;
+}
+
+/**
+ * gtk_drop_target_get_drop:
+ * @self: a #GtkDropTarget
+ *
+ * Gets the currently handled drop operation.
+ *
+ * If no drop operation is going on, %NULL is returned.
+ *
+ * Returns: (nullable) (transfer none): The current drop
+ **/
+GdkDrop *
+gtk_drop_target_get_drop (GtkDropTarget *self)
+{
+  g_return_val_if_fail (GTK_IS_DROP_TARGET (self), NULL);
+
+  return self->drop;
+}
+
+/**
+ * gtk_drop_target_get_value:
+ * @self: a #GtkDropTarget
+ *
+ * Gets the value of the GtkDropTarget:value porperty.
+ *
+ * Returns: (nullable) (transfer none): The current drop data
+ **/
+const GValue *
+gtk_drop_target_get_value (GtkDropTarget *self)
+{
+  g_return_val_if_fail (GTK_IS_DROP_TARGET (self), NULL);
+
+  if (!G_IS_VALUE (&self->value))
+    return NULL;
+
+  return &self->value;
+}
+
+/**
+ * gtk_drop_target_reject:
+ * @self: a #GtkDropTarget
+ *
+ * Rejects the ongoing drop operation.
+ *
+ * If no drop operation is ongoing - when GdkDropTarget:drop
+ * returns %NULL - this function does nothing.
+ *
+ * This function should be used when delaying the decision
+ * on whether to accept a drag or not until after reading
+ * the data.
+ */
+void
+gtk_drop_target_reject (GtkDropTarget *self)
+{
+  g_return_if_fail (GTK_IS_DROP_TARGET (self));
+
+  if (self->drop == NULL)
+    return;
+
+  gtk_drop_target_end_drop (self);
+}
+
diff --git a/gtk/gtkdroptarget.h b/gtk/gtkdroptarget.h
new file mode 100644 (file)
index 0000000..4020f15
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Copyright Â© 2020 Benjamin Otte
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Benjamin Otte <otte@gnome.org>
+ */
+
+#ifndef __GTK_DROP_TARGET_H__
+#define __GTK_DROP_TARGET_H__
+
+
+#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
+#error "Only <gtk/gtk.h> can be included directly."
+#endif
+
+#include <gtk/gtktypes.h>
+
+
+G_BEGIN_DECLS
+
+typedef struct _GtkDropTarget GtkDropTarget;
+
+
+#define GTK_TYPE_DROP_TARGET         (gtk_drop_target_get_type ())
+#define GTK_DROP_TARGET(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GTK_TYPE_DROP_TARGET, GtkDropTarget))
+#define GTK_DROP_TARGET_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST ((k), GTK_TYPE_DROP_TARGET, GtkDropTargetClass))
+#define GTK_IS_DROP_TARGET(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTK_TYPE_DROP_TARGET))
+#define GTK_IS_DROP_TARGET_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), GTK_TYPE_DROP_TARGET))
+#define GTK_DROP_TARGET_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GTK_TYPE_DROP_TARGET, GtkDropTargetClass))
+
+typedef struct _GtkDropTargetClass GtkDropTargetClass;
+
+GDK_AVAILABLE_IN_ALL
+GType                   gtk_drop_target_get_type         (void) G_GNUC_CONST;
+
+GDK_AVAILABLE_IN_ALL
+GtkDropTarget *         gtk_drop_target_new              (GType                  type,
+                                                          GdkDragAction          actions);
+
+GDK_AVAILABLE_IN_ALL
+void                    gtk_drop_target_set_gtypes       (GtkDropTarget         *self,
+                                                          GType                 *types,
+                                                          gsize                  n_types);
+GDK_AVAILABLE_IN_ALL
+const GType *           gtk_drop_target_get_gtypes       (GtkDropTarget         *self,
+                                                          gsize                 *n_types);
+GDK_AVAILABLE_IN_ALL
+GdkContentFormats *     gtk_drop_target_get_formats      (GtkDropTarget         *self);
+
+GDK_AVAILABLE_IN_ALL
+void                    gtk_drop_target_set_actions      (GtkDropTarget         *self,
+                                                          GdkDragAction          actions);
+GDK_AVAILABLE_IN_ALL
+GdkDragAction           gtk_drop_target_get_actions      (GtkDropTarget         *self);
+
+GDK_AVAILABLE_IN_ALL
+void                    gtk_drop_target_set_preload      (GtkDropTarget         *self,
+                                                          gboolean               preload);
+GDK_AVAILABLE_IN_ALL
+gboolean                gtk_drop_target_get_preload      (GtkDropTarget         *self);
+
+GDK_AVAILABLE_IN_ALL
+GdkDrop *               gtk_drop_target_get_drop         (GtkDropTarget         *self);
+
+GDK_AVAILABLE_IN_ALL
+const GValue *          gtk_drop_target_get_value        (GtkDropTarget         *self);
+
+GDK_AVAILABLE_IN_ALL
+void                    gtk_drop_target_reject           (GtkDropTarget         *self);
+
+
+G_END_DECLS
+
+#endif /* __GTK_DROP_TARGET_H__ */
diff --git a/gtk/gtkdroptargetasync.c b/gtk/gtkdroptargetasync.c
new file mode 100644 (file)
index 0000000..0c20619
--- /dev/null
@@ -0,0 +1,673 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 1995-1999 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#include "config.h"
+
+#include "gtkdroptargetasync.h"
+
+#include "gtkdropprivate.h"
+#include "gtkeventcontrollerprivate.h"
+#include "gtkintl.h"
+#include "gtkmarshalers.h"
+#include "gtknative.h"
+#include "gtktypebuiltins.h"
+
+
+/**
+ * SECTION:gtkdroptargetasync
+ * @Short_description: Event controller to receive DND drops
+ * @Title: GtkDropTargetAsync
+ * @See_also: #GtkDropTarget
+ *
+ * GtkDropTargetAsync is an auxiliary object that can be used to receive
+ * Drag-and-Drop operations.  
+ * It is the more complete but also more complex method of handling drop
+ * operations compared to #GtkDropTarget and you should only use it if
+ * #GtkDropTarget doesn't provide all the features you need.
+ *
+ * To use a #GtkDropTargetAsync to receive drops on a widget, you create
+ * a #GtkDropTargetAsync object, configure which data formats and actions
+ * you support, connect to its signals, and then attach
+ * it to the widget with gtk_widget_add_controller().
+ *
+ * During a drag operation, the first signal that a GtkDropTargetAsync
+ * emits is #GtkDropTargetAsync::accept, which is meant to determine
+ * whether the target is a possible drop site for the ongoing drop.
+ * The default handler for the ::accept signal accepts the drop
+ * if it finds a compatible data format and an action that is supported
+ * on both sides.
+ *
+ * If it is, and the widget becomes a target, you will receive a
+ * #GtkDropTargetAsync::drag-enter signal, followed by
+ * #GtkDropTargetAsync::drag-motion signals as the pointer moves,
+ * optionally a #GtkDropTargetAsync::drop signal when a drop happens,
+ * and finally a #GtkDropTargetAsync::drag-leave signal when the pointer
+ * moves off the widget.
+ *
+ * The ::drag-enter and ::drag-motion handler return a #GdkDragAction
+ * to update the status of the ongoing operation. The ::drop handler
+ * should decide if it ultimately accepts the drop and if it does, it
+ * should initiate the data transfer and finish the operation by calling
+ * gdk_drop_finish().
+ *
+ * Between the ::drag-enter and ::drag-leave signals the widget is a
+ * current drop target, and will receive the %GTK_STATE_FLAG_DROP_ACTIVE
+ * state, which can be used by themes to style the widget as a drop target.
+ */
+
+struct _GtkDropTargetAsync
+{
+  GtkEventController parent_object;
+
+  GdkContentFormats *formats;
+  GdkDragAction actions;
+
+  GdkDrop *drop;
+  gboolean rejected;
+};
+
+struct _GtkDropTargetAsyncClass
+{
+  GtkEventControllerClass parent_class;
+
+  gboolean              (* accept)                              (GtkDropTargetAsync     *self,
+                                                                 GdkDrop                *drop);
+  GdkDragAction         (* drag_enter)                          (GtkDropTargetAsync     *self,
+                                                                 GdkDrop                *drop,
+                                                                 double                  x,
+                                                                 double                  y);
+  GdkDragAction         (* drag_motion)                         (GtkDropTargetAsync     *self,
+                                                                 GdkDrop                *drop,
+                                                                 double                  x,
+                                                                 double                  y);
+  void                  (* drag_leave)                          (GtkDropTargetAsync     *self,
+                                                                 GdkDrop                *drop);
+  gboolean              (* drop)                                (GtkDropTargetAsync     *self,
+                                                                 GdkDrop                *drop,
+                                                                 double                  x,
+                                                                 double                  y);
+};
+
+enum {
+  PROP_0,
+  PROP_ACTIONS,
+  PROP_FORMATS,
+  NUM_PROPERTIES
+};
+
+static GParamSpec *properties[NUM_PROPERTIES];
+
+enum {
+  ACCEPT,
+  DRAG_ENTER,
+  DRAG_MOTION,
+  DRAG_LEAVE,
+  DROP,
+  NUM_SIGNALS
+};
+
+static guint signals[NUM_SIGNALS];
+
+G_DEFINE_TYPE (GtkDropTargetAsync, gtk_drop_target_async, GTK_TYPE_EVENT_CONTROLLER);
+
+static gboolean
+gtk_drop_target_async_accept (GtkDropTargetAsync *self,
+                              GdkDrop            *drop)
+{
+  if ((gdk_drop_get_actions (drop) & self->actions) == 0)
+    return FALSE;
+
+  if (self->formats == NULL)
+    return TRUE;
+
+  return gdk_content_formats_match (self->formats, gdk_drop_get_formats (drop));
+}
+
+static GdkDragAction
+make_action_unique (GdkDragAction actions)
+{
+  if (actions & GDK_ACTION_COPY)
+    return GDK_ACTION_COPY;
+
+  if (actions & GDK_ACTION_MOVE)
+    return GDK_ACTION_MOVE;
+  
+  if (actions & GDK_ACTION_LINK)
+    return GDK_ACTION_LINK;
+
+  return 0;
+}
+  
+static GdkDragAction
+gtk_drop_target_async_drag_enter (GtkDropTargetAsync *self,
+                                  GdkDrop            *drop,
+                                  double              x,
+                                  double              y)
+{
+  return make_action_unique (self->actions & gdk_drop_get_actions (drop));
+}
+
+static GdkDragAction         
+gtk_drop_target_async_drag_motion (GtkDropTargetAsync *self,
+                                   GdkDrop            *drop,
+                                   double              x,
+                                   double              y)
+{
+  return make_action_unique (self->actions & gdk_drop_get_actions (drop));
+}
+
+static gboolean
+gtk_drop_target_async_drop (GtkDropTargetAsync  *self,
+                            GdkDrop             *drop,
+                            double               x,
+                            double               y)
+{
+  return FALSE;
+}
+
+static gboolean
+gtk_drop_target_async_filter_event (GtkEventController *controller,
+                                    GdkEvent           *event)
+{
+  switch ((int)gdk_event_get_event_type (event))
+    {
+    case GDK_DRAG_ENTER:
+    case GDK_DRAG_LEAVE:
+    case GDK_DRAG_MOTION:
+    case GDK_DROP_START:
+      return GTK_EVENT_CONTROLLER_CLASS (gtk_drop_target_async_parent_class)->filter_event (controller, event);
+
+    default:;
+    }
+
+  return TRUE;
+}
+
+static gboolean
+gtk_drop_target_async_handle_event (GtkEventController *controller,
+                                    GdkEvent           *event,
+                                    double              x,
+                                    double              y)
+{
+  GtkDropTargetAsync *self = GTK_DROP_TARGET_ASYNC (controller);
+  GdkDrop *drop;
+
+  switch ((int) gdk_event_get_event_type (event))
+    {
+    case GDK_DRAG_MOTION:
+      {
+        GtkWidget *widget = gtk_event_controller_get_widget (controller);
+        GdkDragAction preferred_action;
+
+        drop = gdk_drag_event_get_drop (event);
+        /* sanity check */
+        g_return_val_if_fail (self->drop == drop, FALSE);
+        if (self->rejected)
+          return FALSE;
+
+        g_signal_emit (self, signals[DRAG_MOTION], 0, drop, x, y, &preferred_action);
+        if (preferred_action &&
+            gtk_drop_status (self->drop, self->actions, preferred_action))
+          {
+            gtk_widget_set_state_flags (widget, GTK_STATE_FLAG_DROP_ACTIVE, FALSE);
+          }
+        else
+          {
+            gtk_widget_unset_state_flags (widget, GTK_STATE_FLAG_DROP_ACTIVE);
+          }
+      }
+      return FALSE;
+
+    case GDK_DROP_START:
+      {
+        gboolean handled;
+
+        drop = gdk_drag_event_get_drop (event);
+        /* sanity check */
+        g_return_val_if_fail (self->drop == drop, FALSE);
+        if (self->rejected)
+          return FALSE;
+
+        g_signal_emit (self, signals[DROP], 0, self->drop, x, y, &handled);
+        return handled;
+      }
+
+    default:
+      return FALSE;
+    }
+}
+
+static void
+gtk_drop_target_async_handle_crossing (GtkEventController    *controller,
+                                 const GtkCrossingData *crossing,
+                                 double                 x,
+                                 double                 y)
+{
+  GtkDropTargetAsync *self = GTK_DROP_TARGET_ASYNC (controller);
+  GtkWidget *widget = gtk_event_controller_get_widget (controller);
+
+  if (crossing->type != GTK_CROSSING_DROP)
+    return;
+
+  /* sanity check */
+  g_warn_if_fail (self->drop == NULL || self->drop == crossing->drop);
+
+  if (crossing->direction == GTK_CROSSING_IN)
+    {
+      gboolean accept = FALSE;
+      GdkDragAction preferred_action;
+
+      if (self->drop != NULL)
+        return;
+
+      self->drop = g_object_ref (crossing->drop);
+
+      g_signal_emit (self, signals[ACCEPT], 0, self->drop, &accept);
+      self->rejected = !accept;
+      if (self->rejected)
+        return;
+
+      g_signal_emit (self, signals[DRAG_ENTER], 0, self->drop, x, y, &preferred_action);
+      if (preferred_action &&
+          gtk_drop_status (self->drop, self->actions, preferred_action))
+        {
+          gtk_widget_set_state_flags (widget, GTK_STATE_FLAG_DROP_ACTIVE, FALSE);
+        }
+    }
+  else
+    {
+      if (crossing->new_descendent != NULL ||
+          crossing->new_target == widget)
+        return;
+
+      g_signal_emit (self, signals[DRAG_LEAVE], 0, self->drop);
+      g_clear_object (&self->drop);
+      gtk_widget_unset_state_flags (widget, GTK_STATE_FLAG_DROP_ACTIVE);
+    }
+}
+
+static void
+gtk_drop_target_async_finalize (GObject *object)
+{
+  GtkDropTargetAsync *self = GTK_DROP_TARGET_ASYNC (object);
+
+  g_clear_pointer (&self->formats, gdk_content_formats_unref);
+
+  G_OBJECT_CLASS (gtk_drop_target_async_parent_class)->finalize (object);
+}
+
+static void
+gtk_drop_target_async_set_property (GObject      *object,
+                                    guint         prop_id,
+                                    const GValue *value,
+                                    GParamSpec   *pspec)
+{
+  GtkDropTargetAsync *self = GTK_DROP_TARGET_ASYNC (object);
+
+  switch (prop_id)
+    {
+    case PROP_ACTIONS:
+      gtk_drop_target_async_set_actions (self, g_value_get_flags (value));
+      break;
+
+    case PROP_FORMATS:
+      gtk_drop_target_async_set_formats (self, g_value_get_boxed (value));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gtk_drop_target_async_get_property (GObject    *object,
+                            guint       prop_id,
+                            GValue     *value,
+                            GParamSpec *pspec)
+{
+  GtkDropTargetAsync *self = GTK_DROP_TARGET_ASYNC (object);
+
+  switch (prop_id)
+    {
+    case PROP_ACTIONS:
+      g_value_set_flags (value, gtk_drop_target_async_get_actions (self));
+      break;
+
+    case PROP_FORMATS:
+      g_value_set_boxed (value, gtk_drop_target_async_get_formats (self));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gtk_drop_target_async_class_init (GtkDropTargetAsyncClass *class)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (class);
+  GtkEventControllerClass *controller_class = GTK_EVENT_CONTROLLER_CLASS (class);
+
+  object_class->finalize = gtk_drop_target_async_finalize;
+  object_class->set_property = gtk_drop_target_async_set_property;
+  object_class->get_property = gtk_drop_target_async_get_property;
+
+  controller_class->handle_event = gtk_drop_target_async_handle_event;
+  controller_class->filter_event = gtk_drop_target_async_filter_event;
+  controller_class->handle_crossing = gtk_drop_target_async_handle_crossing;
+
+  class->accept = gtk_drop_target_async_accept;
+  class->drag_enter = gtk_drop_target_async_drag_enter;
+  class->drag_motion = gtk_drop_target_async_drag_motion;
+  class->drop = gtk_drop_target_async_drop;
+
+  /**
+   * GtkDropTargetAsync:actions:
+   *
+   * The #GdkDragActions that this drop target supports
+   */ 
+  properties[PROP_ACTIONS] =
+       g_param_spec_flags ("actions", P_("Actions"), P_("Actions"),
+                           GDK_TYPE_DRAG_ACTION, 0,
+                           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
+
+  /**
+   * GtkDropTargetAsync:formats:
+   *
+   * The #GdkContentFormats that determines the supported data formats
+   */
+  properties[PROP_FORMATS] =
+       g_param_spec_boxed ("formats", P_("Formats"), P_("Formats"),
+                           GDK_TYPE_CONTENT_FORMATS,
+                           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
+
+  g_object_class_install_properties (object_class, NUM_PROPERTIES, properties);
+
+ /**
+   * GtkWidget::accept:
+   * @self: the #GtkDropTargetAsync
+   * @drop: the #GdkDrop
+   *
+   * The ::accept signal is emitted on the drop site when a drop operation
+   * is about to begin.  
+   * If the drop is not accepted, %FALSE will be returned and the drop target
+   * will ignore the drop. If %TRUE is returned, the drop is accepted for now
+   * but may be rejected later via a call to gtk_drop_target_reject() or
+   * ultimately by returning %FALSE from GtkDropTarget::drop
+   *
+   * The default handler for this signal decides whether to accept the drop
+   * based on the formats provided by the @drop.
+   *
+   * If the decision whether the drop will be accepted or rejected needs
+   * further procesing, such as inspecting the data, this function should
+   * return %TRUE and proceed as is @drop was accepted and if it decides to
+   * reject the drop later, it should call gtk_drop_target_reject_drop().
+   *
+   * Returns: %TRUE if @drop is accepted
+   */
+  signals[ACCEPT] =
+      g_signal_new (I_("accept"),
+                    G_TYPE_FROM_CLASS (class),
+                    G_SIGNAL_RUN_LAST,
+                    G_STRUCT_OFFSET (GtkDropTargetAsyncClass, accept),
+                    g_signal_accumulator_first_wins, NULL,
+                    NULL,
+                    G_TYPE_BOOLEAN, 1,
+                    GDK_TYPE_DROP);
+
+  /**
+   * GtkDropTargetAsync::drag-enter:
+   * @self: the #GtkDropTargetAsync
+   * @drop: the #GdkDrop
+   * @x: the x coordinate of the current pointer position
+   * @y: the y coordinate of the current pointer position
+   *
+   * The ::drag-enter signal is emitted on the drop site when the pointer
+   * enters the widget. It can be used to set up custom highlighting.
+   *
+   * Returns: Preferred action for this drag operation. 
+   */
+  signals[DRAG_ENTER] =
+      g_signal_new (I_("drag-enter"),
+                    G_TYPE_FROM_CLASS (class),
+                    G_SIGNAL_RUN_LAST,
+                    G_STRUCT_OFFSET (GtkDropTargetAsyncClass, drag_enter),
+                    g_signal_accumulator_first_wins, NULL,
+                    NULL,
+                    GDK_TYPE_DRAG_ACTION, 3,
+                    GDK_TYPE_DROP, G_TYPE_DOUBLE, G_TYPE_DOUBLE);
+
+  /**
+   * GtkDropTargetAsync::drag-motion:
+   * @self: the #GtkDropTargetAsync
+   * @drop: the #GdkDrop
+   * @x: the x coordinate of the current pointer position
+   * @y: the y coordinate of the current pointer position
+   *
+   * The ::drag-motion signal is emitted while the pointer is moving
+   * over the drop target.
+   *
+   * Returns: Preferred action for this drag operation. 
+   */
+  signals[DRAG_MOTION] =
+      g_signal_new (I_("drag-motion"),
+                    G_TYPE_FROM_CLASS (class),
+                    G_SIGNAL_RUN_LAST,
+                    G_STRUCT_OFFSET (GtkDropTargetAsyncClass, drag_motion),
+                    g_signal_accumulator_first_wins, NULL,
+                    NULL,
+                    GDK_TYPE_DRAG_ACTION, 3,
+                    GDK_TYPE_DROP, G_TYPE_DOUBLE, G_TYPE_DOUBLE);
+
+  /**
+   * GtkDropTargetAsync::drag-leave:
+   * @self: the #GtkDropTargetAsync
+   * @drop: the #GdkDrop
+   *
+   * The ::drag-leave signal is emitted on the drop site when the pointer
+   * leaves the widget. Its main purpose it to undo things done in
+   * #GtkDropTargetAsync::drag-enter.
+   */
+  signals[DRAG_LEAVE] =
+      g_signal_new (I_("drag-leave"),
+                    G_TYPE_FROM_CLASS (class),
+                    G_SIGNAL_RUN_LAST,
+                    G_STRUCT_OFFSET (GtkDropTargetAsyncClass, drag_leave),
+                    NULL, NULL,
+                    NULL,
+                    G_TYPE_NONE, 1,
+                    GDK_TYPE_DROP);
+
+  /**
+   * GtkDropTargetAsync::drop:
+   * @self: the #GtkDropTargetAsync
+   * @drop: the #GdkDrop
+   * @x: the x coordinate of the current pointer position
+   * @y: the y coordinate of the current pointer position
+   *
+   * The ::drop signal is emitted on the drop site when the user drops
+   * the data onto the widget. The signal handler must determine whether
+   * the pointer position is in a drop zone or not. If it is not in a drop
+   * zone, it returns %FALSE and no further processing is necessary.
+   *
+   * Otherwise, the handler returns %TRUE. In this case, this handler will
+   * accept the drop. The handler must ensure that gdk_drop_finish() is
+   * called to let the source know that the drop is done. The call to
+   * gtk_drag_finish() must only be done when all data has been received.
+   *
+   * To receive the data, use one of the read functions provides by #GdkDrop
+   * such as gdk_drop_read_async() or gdk_drop_read_value_async().
+   *
+   * Returns: whether the drop is accepted at the given pointer position
+   */
+  signals[DROP] =
+      g_signal_new (I_("drop"),
+                    G_TYPE_FROM_CLASS (class),
+                    G_SIGNAL_RUN_LAST,
+                    0,
+                    g_signal_accumulator_first_wins, NULL,
+                    NULL,
+                    G_TYPE_BOOLEAN, 3,
+                    GDK_TYPE_DROP, G_TYPE_DOUBLE, G_TYPE_DOUBLE);
+}
+
+static void
+gtk_drop_target_async_init (GtkDropTargetAsync *self)
+{
+}
+
+/**
+ * gtk_drop_target_async_new:
+ * @formats: (nullable) (transfer full): the supported data formats
+ * @actions: the supported actions
+ *
+ * Creates a new #GtkDropTargetAsync object.
+ *
+ * Returns: the new #GtkDropTargetAsync
+ */
+GtkDropTargetAsync *
+gtk_drop_target_async_new (GdkContentFormats *formats,
+                     GdkDragAction      actions)
+{
+  GtkDropTargetAsync *result;
+
+  result = g_object_new (GTK_TYPE_DROP_TARGET_ASYNC,
+                         "formats", formats,
+                         "actions", actions,
+                         NULL);
+
+  g_clear_pointer (&formats, gdk_content_formats_unref);
+
+  return result;
+}
+
+/**
+ * gtk_drop_target_async_set_formats:
+ * @self: a #GtkDropTargetAsync
+ * @formats: (nullable): the supported data formats or %NULL for
+ *     any format.
+ *
+ * Sets the data formats that this drop target will accept.
+ */
+void
+gtk_drop_target_async_set_formats (GtkDropTargetAsync *self,
+                                   GdkContentFormats  *formats)
+{
+  g_return_if_fail (GTK_IS_DROP_TARGET_ASYNC (self));
+
+  if (self->formats == formats)
+    return;
+
+  if (self->formats)
+    gdk_content_formats_unref (self->formats);
+
+  self->formats = formats;
+
+  if (self->formats)
+    gdk_content_formats_ref (self->formats);
+
+  g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FORMATS]);
+}
+
+/**
+ * gtk_drop_target_async_get_formats:
+ * @self: a #GtkDropTargetAsync
+ *
+ * Gets the data formats that this drop target accepts.
+ *
+ * If the result is %NULL, all formats are expected to be supported.
+ *
+ * Returns: (nullable): the supported data formats
+ */
+GdkContentFormats *
+gtk_drop_target_async_get_formats (GtkDropTargetAsync *self)
+{
+  g_return_val_if_fail (GTK_IS_DROP_TARGET_ASYNC (self), NULL);
+  
+  return self->formats;
+}
+
+/**
+ * gtk_drop_target_async_set_actions:
+ * @self: a #GtkDropTargetAsync
+ * @actions: the supported actions
+ *
+ * Sets the actions that this drop target supports.
+ */
+void
+gtk_drop_target_async_set_actions (GtkDropTargetAsync *self,
+                                   GdkDragAction       actions)
+{
+  g_return_if_fail (GTK_IS_DROP_TARGET_ASYNC (self));
+  
+  if (self->actions == actions)
+    return;
+
+  self->actions = actions;
+
+  g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ACTIONS]);
+}
+
+/**
+ * gtk_drop_target_async_get_actions:
+ * @self: a #GtkDropTargetAsync
+ *
+ * Gets the actions that this drop target supports.
+ *
+ * Returns: the actions that this drop target supports
+ */
+GdkDragAction
+gtk_drop_target_async_get_actions (GtkDropTargetAsync *self)
+{
+  g_return_val_if_fail (GTK_IS_DROP_TARGET_ASYNC (self), 0);
+
+  return self->actions;
+}
+
+/**
+ * gtk_drop_target_async_reject_drop:
+ * @self: a #GtkDropTargetAsync
+ * @drop: the #GdkDrop of an ongoing drag operation
+ *
+ * Sets the @drop as not accepted on this drag site.
+ *
+ * This function should be used when delaying the decision
+ * on whether to accept a drag or not until after reading
+ * the data.
+ */
+void
+gtk_drop_target_async_reject_drop (GtkDropTargetAsync *self,
+                                   GdkDrop            *drop)
+{
+  g_return_if_fail (GTK_IS_DROP_TARGET_ASYNC (self));
+  g_return_if_fail (GDK_IS_DROP (drop));
+  g_return_if_fail (self->drop == drop);
+
+  if (self->rejected)
+    return;
+
+  self->rejected = TRUE;
+  gtk_widget_unset_state_flags (gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (self)),
+                                GTK_STATE_FLAG_DROP_ACTIVE);
+}
diff --git a/gtk/gtkdroptargetasync.h b/gtk/gtkdroptargetasync.h
new file mode 100644 (file)
index 0000000..6e9578a
--- /dev/null
@@ -0,0 +1,77 @@
+/* -*- Mode: C; c-file-style: "gnu"; tab-width: 8 -*- */
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#ifndef __GTK_DROP_TARGET_ASYNC_H__
+#define __GTK_DROP_TARGET_ASYNC_H__
+
+
+#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
+#error "Only <gtk/gtk.h> can be included directly."
+#endif
+
+#include <gtk/gtkwidget.h>
+
+
+G_BEGIN_DECLS
+
+typedef struct _GtkDropTargetAsync GtkDropTargetAsync;
+typedef struct _GtkDropTargetAsyncClass GtkDropTargetAsyncClass;
+
+
+#define GTK_TYPE_DROP_TARGET_ASYNC         (gtk_drop_target_async_get_type ())
+#define GTK_DROP_TARGET_ASYNC(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GTK_TYPE_DROP_TARGET_ASYNC, GtkDropTargetAsync))
+#define GTK_DROP_TARGET_ASYNC_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST ((k), GTK_TYPE_DROP_TARGET_ASYNC, GtkDropTargetAsyncClass))
+#define GTK_IS_DROP_TARGET_ASYNC(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTK_TYPE_DROP_TARGET_ASYNC))
+#define GTK_IS_DROP_TARGET_ASYNC_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), GTK_TYPE_DROP_TARGET_ASYNC))
+#define GTK_DROP_TARGET_ASYNC_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GTK_TYPE_DROP_TARGET_ASYNC, GtkDropTargetAsyncClass))
+
+
+GDK_AVAILABLE_IN_ALL
+GType                   gtk_drop_target_async_get_type          (void) G_GNUC_CONST;
+
+GDK_AVAILABLE_IN_ALL
+GtkDropTargetAsync *    gtk_drop_target_async_new               (GdkContentFormats      *formats,
+                                                                 GdkDragAction           actions);
+
+GDK_AVAILABLE_IN_ALL
+void                    gtk_drop_target_async_set_formats       (GtkDropTargetAsync     *self,
+                                                                 GdkContentFormats      *formats);
+GDK_AVAILABLE_IN_ALL
+GdkContentFormats *     gtk_drop_target_async_get_formats       (GtkDropTargetAsync     *self);
+
+GDK_AVAILABLE_IN_ALL
+void                    gtk_drop_target_async_set_actions       (GtkDropTargetAsync     *self,
+                                                                 GdkDragAction           actions);
+GDK_AVAILABLE_IN_ALL
+GdkDragAction           gtk_drop_target_async_get_actions       (GtkDropTargetAsync     *self);
+
+GDK_AVAILABLE_IN_ALL
+void                    gtk_drop_target_async_reject_drop       (GtkDropTargetAsync     *self,
+                                                                 GdkDrop                *drop);
+
+
+G_END_DECLS
+
+#endif /* __GTK_DROP_TARGET_ASYNC_H__ */
index f73f52add856efc7e7dae1e313073d21f4ba6b52..ce15326723b19a3676f5a43b960c2e1f348da440 100644 (file)
@@ -37,7 +37,7 @@
 #include "gtkcellrendererpixbuf.h"
 #include "gtkcombobox.h"
 #include "gtkcssiconthemevalueprivate.h"
-#include "gtkdragdest.h"
+#include "gtkdroptarget.h"
 #include "gtkicontheme.h"
 #include "gtkimage.h"
 #include "gtklabel.h"
@@ -268,11 +268,6 @@ static void     gtk_file_chooser_button_finalize           (GObject          *ob
 
 /* GtkWidget Functions */
 static void     gtk_file_chooser_button_destroy            (GtkWidget        *widget);
-static gboolean gtk_file_chooser_button_drag_drop          (GtkDropTarget    *dest,
-                                                            GdkDrop          *drop,
-                                                            int               x,
-                                                            int               y,
-                                                           GtkWidget        *widget);
 static void     gtk_file_chooser_button_show               (GtkWidget        *widget);
 static void     gtk_file_chooser_button_hide               (GtkWidget        *widget);
 static void     gtk_file_chooser_button_root               (GtkWidget *widget);
@@ -350,6 +345,115 @@ G_DEFINE_TYPE_WITH_CODE (GtkFileChooserButton, gtk_file_chooser_button, GTK_TYPE
                          G_IMPLEMENT_INTERFACE (GTK_TYPE_FILE_CHOOSER,
                                                 gtk_file_chooser_button_file_chooser_iface_init))
 
+struct DndSelectFolderData
+{
+  GtkFileSystem *file_system;
+  GtkFileChooserButton *button;
+  GtkFileChooserAction action;
+  GFile *file;
+  gchar **uris;
+  guint i;
+  gboolean selected;
+};
+
+static void
+dnd_select_folder_get_info_cb (GCancellable *cancellable,
+                              GFileInfo    *info,
+                              const GError *error,
+                              gpointer      user_data)
+{
+  struct DndSelectFolderData *data = user_data;
+  GtkFileChooserButton *button = data->button;
+  GtkFileChooserButtonPrivate *priv = gtk_file_chooser_button_get_instance_private (button);
+  gboolean cancelled = g_cancellable_is_cancelled (cancellable);
+
+  if (cancellable != priv->dnd_select_folder_cancellable)
+    {
+      g_object_unref (data->button);
+      g_object_unref (data->file);
+      g_strfreev (data->uris);
+      g_free (data);
+
+      g_object_unref (cancellable);
+      return;
+    }
+
+  priv->dnd_select_folder_cancellable = NULL;
+
+  if (!cancelled && !error && info != NULL)
+    {
+      gboolean is_folder;
+
+      is_folder = _gtk_file_info_consider_as_directory (info);
+
+      data->selected =
+       (((data->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER && is_folder) ||
+         (data->action == GTK_FILE_CHOOSER_ACTION_OPEN && !is_folder)) &&
+        gtk_file_chooser_select_file (GTK_FILE_CHOOSER (data->button), data->file, NULL));
+    }
+  else
+    data->selected = FALSE;
+
+  if (data->selected || data->uris[++data->i] == NULL)
+    {
+      g_signal_emit (data->button, file_chooser_button_signals[FILE_SET], 0);
+
+      g_object_unref (data->button);
+      g_object_unref (data->file);
+      g_strfreev (data->uris);
+      g_free (data);
+
+      g_object_unref (cancellable);
+      return;
+    }
+
+  if (data->file)
+    g_object_unref (data->file);
+
+  data->file = g_file_new_for_uri (data->uris[data->i]);
+
+  priv->dnd_select_folder_cancellable =
+    _gtk_file_system_get_info (data->file_system, data->file,
+                               "standard::type",
+                               dnd_select_folder_get_info_cb, user_data);
+
+  g_object_unref (cancellable);
+}
+
+static gboolean
+gtk_file_chooser_button_drop (GtkDropTarget        *target,
+                              const GValue         *value,
+                              double                x,
+                              double                y,
+                              GtkFileChooserButton *button)
+{
+  GtkFileChooserButtonPrivate *priv = gtk_file_chooser_button_get_instance_private (button);
+  struct DndSelectFolderData *info;
+  GFile *file;
+
+  file = g_value_get_object (value);
+
+  info = g_new0 (struct DndSelectFolderData, 1);
+  info->button = g_object_ref (button);
+  info->i = 0;
+  info->uris = g_new0 (char *, 2);
+  info->selected = FALSE;
+  info->file_system = priv->fs;
+  g_object_get (priv->chooser, "action", &info->action, NULL);
+
+  info->file = g_object_ref (file);
+
+  if (priv->dnd_select_folder_cancellable)
+    g_cancellable_cancel (priv->dnd_select_folder_cancellable);
+
+  priv->dnd_select_folder_cancellable =
+    _gtk_file_system_get_info (priv->fs, info->file,
+                               "standard::type",
+                               dnd_select_folder_get_info_cb, info);
+
+  return TRUE;
+}
+
 static void
 gtk_file_chooser_button_class_init (GtkFileChooserButtonClass * class)
 {
@@ -441,8 +545,7 @@ gtk_file_chooser_button_init (GtkFileChooserButton *button)
   GtkFileChooserButtonPrivate *priv = gtk_file_chooser_button_get_instance_private (button);
   GtkWidget *box;
   GtkWidget *icon;
-  GdkContentFormatsBuilder *builder;
-  GtkDropTarget *dest;
+  GtkDropTarget *target;
 
   priv->button = gtk_button_new ();
   g_signal_connect (priv->button, "clicked", G_CALLBACK (button_clicked_cb), button);
@@ -494,13 +597,9 @@ gtk_file_chooser_button_init (GtkFileChooserButton *button)
                                      NULL, NULL);
 
   /* DnD */
-  builder = gdk_content_formats_builder_new ();
-  gdk_content_formats_builder_add_gtype (builder, G_TYPE_STRING);
-  gdk_content_formats_builder_add_gtype (builder, GDK_TYPE_FILE_LIST);
-  dest = gtk_drop_target_new (gdk_content_formats_builder_free_to_formats (builder),
-                              GDK_ACTION_COPY);
-  g_signal_connect (dest, "drag-drop", G_CALLBACK (gtk_file_chooser_button_drag_drop), button);
-  gtk_widget_add_controller (GTK_WIDGET (button), GTK_EVENT_CONTROLLER (dest));
+  target = gtk_drop_target_new (G_TYPE_FILE, GDK_ACTION_COPY);
+  g_signal_connect (target, "drop", G_CALLBACK (gtk_file_chooser_button_drop), button);
+  gtk_widget_add_controller (GTK_WIDGET (button), GTK_EVENT_CONTROLLER (target));
 }
 
 
@@ -1045,169 +1144,6 @@ gtk_file_chooser_button_destroy (GtkWidget *widget)
   GTK_WIDGET_CLASS (gtk_file_chooser_button_parent_class)->destroy (widget);
 }
 
-struct DndSelectFolderData
-{
-  GtkFileSystem *file_system;
-  GtkFileChooserButton *button;
-  GtkFileChooserAction action;
-  GFile *file;
-  gchar **uris;
-  guint i;
-  gboolean selected;
-};
-
-static void
-dnd_select_folder_get_info_cb (GCancellable *cancellable,
-                              GFileInfo    *info,
-                              const GError *error,
-                              gpointer      user_data)
-{
-  struct DndSelectFolderData *data = user_data;
-  GtkFileChooserButton *button = data->button;
-  GtkFileChooserButtonPrivate *priv = gtk_file_chooser_button_get_instance_private (button);
-  gboolean cancelled = g_cancellable_is_cancelled (cancellable);
-
-  if (cancellable != priv->dnd_select_folder_cancellable)
-    {
-      g_object_unref (data->button);
-      g_object_unref (data->file);
-      g_strfreev (data->uris);
-      g_free (data);
-
-      g_object_unref (cancellable);
-      return;
-    }
-
-  priv->dnd_select_folder_cancellable = NULL;
-
-  if (!cancelled && !error && info != NULL)
-    {
-      gboolean is_folder;
-
-      is_folder = _gtk_file_info_consider_as_directory (info);
-
-      data->selected =
-       (((data->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER && is_folder) ||
-         (data->action == GTK_FILE_CHOOSER_ACTION_OPEN && !is_folder)) &&
-        gtk_file_chooser_select_file (GTK_FILE_CHOOSER (data->button), data->file, NULL));
-    }
-  else
-    data->selected = FALSE;
-
-  if (data->selected || data->uris[++data->i] == NULL)
-    {
-      g_signal_emit (data->button, file_chooser_button_signals[FILE_SET], 0);
-
-      g_object_unref (data->button);
-      g_object_unref (data->file);
-      g_strfreev (data->uris);
-      g_free (data);
-
-      g_object_unref (cancellable);
-      return;
-    }
-
-  if (data->file)
-    g_object_unref (data->file);
-
-  data->file = g_file_new_for_uri (data->uris[data->i]);
-
-  priv->dnd_select_folder_cancellable =
-    _gtk_file_system_get_info (data->file_system, data->file,
-                               "standard::type",
-                               dnd_select_folder_get_info_cb, user_data);
-
-  g_object_unref (cancellable);
-}
-
-static void
-dnd_select_file (GtkFileChooserButton *button,
-                 GFile                *file)
-{
-  GtkFileChooserButtonPrivate *priv = gtk_file_chooser_button_get_instance_private (button);
-  struct DndSelectFolderData *info;
-
-  info = g_new0 (struct DndSelectFolderData, 1);
-  info->button = g_object_ref (button);
-  info->i = 0;
-  info->uris = g_new0 (char *, 2);
-  info->selected = FALSE;
-  info->file_system = priv->fs;
-  g_object_get (priv->chooser, "action", &info->action, NULL);
-
-  info->file = g_object_ref (file);
-
-  if (priv->dnd_select_folder_cancellable)
-    g_cancellable_cancel (priv->dnd_select_folder_cancellable);
-
-  priv->dnd_select_folder_cancellable =
-    _gtk_file_system_get_info (priv->fs, info->file,
-                               "standard::type",
-                               dnd_select_folder_get_info_cb, info);
-}
-
-static void
-got_file (GObject      *source,
-          GAsyncResult *result,
-          gpointer      data)
-{
-  GtkFileChooserButton *button = GTK_FILE_CHOOSER_BUTTON (data);
-  GdkDrop *drop = GDK_DROP (source);
-  const GValue *value;
-
-  value = gdk_drop_read_value_finish (drop, result, NULL);
-  if (value)
-    {
-      GFile *file;
-
-      file = g_value_get_object (value);
-      dnd_select_file (button, file);
-    }
-}
-
-static void
-got_text (GObject      *source,
-          GAsyncResult *result,
-          gpointer      data)
-{
-  GtkFileChooserButton *button = GTK_FILE_CHOOSER_BUTTON (data);
-  GdkDrop *drop = GDK_DROP (source);
-  char *str;
-
-  str = gdk_drop_read_text_finish (drop, result, NULL);
-  if (str)
-    {
-      GFile *file;
-
-      file = g_file_new_for_uri (str);
-      dnd_select_file (button, file);
-      g_object_unref (file);
-    }
-
-}
-
-static gboolean
-gtk_file_chooser_button_drag_drop (GtkDropTarget *dest,
-                                   GdkDrop       *drop,
-                                   int            x,
-                                   int            y,
-                                   GtkWidget     *button)
-{
-  if (gdk_drop_has_value (drop, G_TYPE_FILE))
-    {
-      gdk_drop_read_value_async (drop, G_TYPE_FILE, G_PRIORITY_DEFAULT, NULL, got_file, button);
-      return TRUE;
-    }
-  else
-    {
-      gdk_drop_read_text_async (drop, NULL, got_text, button);
-      return TRUE;
-    }
-
-  return FALSE;
-
-}
-
 static void
 gtk_file_chooser_button_show (GtkWidget *widget)
 {
index 946066346873d3c263ee15cdd0a3e60ab18c7d6d..1b6a03826f376947d03b5e156d7b9e6705ad64d9 100644 (file)
@@ -31,7 +31,7 @@
 #include "gtkcomboboxtext.h"
 #include "gtkcssnumbervalueprivate.h"
 #include "gtkdragsource.h"
-#include "gtkdragdest.h"
+#include "gtkdroptarget.h"
 #include "gtkentry.h"
 #include "gtkfilechooserprivate.h"
 #include "gtkfilechooserdialog.h"
@@ -1839,25 +1839,17 @@ out:
   g_object_unref (cancellable);
 }
 
-static void
-file_list_drag_data_received_cb (GObject      *source,
-                                 GAsyncResult *result,
-                                 gpointer      user_data)
+static gboolean
+file_list_drag_drop_cb (GtkDropTarget        *dest,
+                        const GValue         *value,
+                        double                x,
+                        double                y,
+                        GtkFileChooserWidget *impl)
 {
-  GtkFileChooserWidget *impl = GTK_FILE_CHOOSER_WIDGET (user_data);
   GtkFileChooserWidgetPrivate *priv = gtk_file_chooser_widget_get_instance_private (impl);
-  GdkDrop *drop = GDK_DROP (source);
   GSList *files;
-  const GValue *value;
   FileListDragData *data;
 
-  value = gdk_drop_read_value_finish (drop, result, NULL);
-  if (value == NULL)
-    {
-      gdk_drop_finish (drop, 0);
-      return;
-    }
-
   files = g_value_get_boxed (value);
 
   data = g_new0 (FileListDragData, 1);
@@ -1873,30 +1865,6 @@ file_list_drag_data_received_cb (GObject      *source,
                                file_list_drag_data_received_get_info_cb,
                                    data);
 
-  gdk_drop_finish (drop, gdk_drop_get_actions (drop));
-}
-
-/* Don't do anything with the drag_drop signal */
-static gboolean
-file_list_drag_drop_cb (GtkDropTarget        *dest,
-                        GdkDrop              *drop,
-                        int                   x,
-                        int                   y,
-                        GtkFileChooserWidget *impl)
-{
-  gdk_drop_read_value_async (drop, GDK_TYPE_FILE_LIST, G_PRIORITY_DEFAULT, NULL, file_list_drag_data_received_cb, impl);
-
-  return TRUE;
-}
-
-/* Disable the normal tree drag motion handler, it makes it look like you're
-   dropping the dragged item onto a tree item */
-static gboolean
-file_list_drag_accept_cb (GtkDropTarget        *dest,
-                          GdkDrop              *drop,
-                          GtkFileChooserWidget *impl)
-{
-  g_signal_stop_emission_by_name (dest, "accept");
   return TRUE;
 }
 
@@ -7954,7 +7922,7 @@ post_process_ui (GtkFileChooserWidget *impl)
   GtkCellRenderer  *cell;
   GList            *cells;
   GFile            *file;
-  GtkDropTarget *dest;
+  GtkDropTarget *target;
 
   /* Setup file list treeview */
   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->browse_files_tree_view));
@@ -7966,11 +7934,9 @@ post_process_ui (GtkFileChooserWidget *impl)
                                           gdk_content_formats_new_for_gtype (GDK_TYPE_FILE_LIST),
                                           GDK_ACTION_COPY | GDK_ACTION_MOVE);
   
-  dest = gtk_drop_target_new (gdk_content_formats_new_for_gtype (GDK_TYPE_FILE_LIST),
-                              GDK_ACTION_COPY | GDK_ACTION_MOVE);
-  g_signal_connect (dest, "accept", G_CALLBACK (file_list_drag_accept_cb), impl);
-  g_signal_connect (dest, "drag-drop", G_CALLBACK (file_list_drag_drop_cb), impl);
-  gtk_widget_add_controller (priv->browse_files_tree_view, GTK_EVENT_CONTROLLER (dest));
+  target = gtk_drop_target_new (GDK_TYPE_FILE_LIST, GDK_ACTION_COPY | GDK_ACTION_MOVE);
+  g_signal_connect (target, "drop", G_CALLBACK (file_list_drag_drop_cb), impl);
+  gtk_widget_add_controller (priv->browse_files_tree_view, GTK_EVENT_CONTROLLER (target));
 
   /* File browser treemodel columns are shared between GtkFileChooser implementations,
    * so we don't set cell renderer attributes in GtkBuilder, but rather keep that
index 9400fdd24b18af94e0c2969fe5c4f5a30b9b9bf4..acaf40f10d51abaaba8bfb2db4525bb334d3eefe 100644 (file)
@@ -30,7 +30,6 @@
 #include "gtkcellrenderertext.h"
 #include "gtkcombobox.h"
 #include "gtkcssnodeprivate.h"
-#include "gtkdragdest.h"
 #include "gtkdragsource.h"
 #include "gtkentry.h"
 #include "gtkintl.h"
@@ -48,7 +47,6 @@
 #include "gtkwindow.h"
 #include "gtkeventcontrollerkey.h"
 #include "gtkdragsource.h"
-#include "gtkdragdest.h"
 #include "gtkdragicon.h"
 #include "gtknative.h"
 
@@ -287,19 +285,19 @@ static GdkContentProvider * gtk_icon_view_drag_data_get                  (GtkIco
                                                                           GtkTreePath            *source_row);
 
 /* Target side drag signals */
-static void     gtk_icon_view_drag_leave         (GtkDropTarget    *dest,
-                                                  GdkDrop          *drop,
-                                                  GtkIconView      *icon_view);
-static void     gtk_icon_view_drag_motion        (GtkDropTarget    *dest,
-                                                  GdkDrop          *drop,
-                                                  int               x,
-                                                  int               y,
-                                                  GtkIconView      *icon_view);
-static gboolean gtk_icon_view_drag_drop          (GtkDropTarget    *dest,
-                                                  GdkDrop          *drop,
-                                                  int               x,
-                                                  int               y,
-                                                  GtkIconView      *icon_view);
+static void                 gtk_icon_view_drag_leave                     (GtkDropTargetAsync     *dest,
+                                                                          GdkDrop                *drop,
+                                                                          GtkIconView            *icon_view);
+static GdkDragAction        gtk_icon_view_drag_motion                    (GtkDropTargetAsync     *dest,
+                                                                          GdkDrop                *drop,
+                                                                          double                  x,
+                                                                          double                  y,
+                                                                          GtkIconView            *icon_view);
+static gboolean             gtk_icon_view_drag_drop                      (GtkDropTargetAsync     *dest,
+                                                                          GdkDrop                *drop,
+                                                                          double                  x,
+                                                                          double                  y,
+                                                                          GtkIconView            *icon_view);
 static void     gtk_icon_view_drag_data_received (GObject          *source,
                                                   GAsyncResult     *result,
                                                   gpointer          data);
@@ -5828,12 +5826,12 @@ drag_scroll_timeout (gpointer data)
 }
 
 static gboolean
-set_destination (GtkIconView    *icon_view,
-                GtkDropTarget  *dest,
-                gint            x,
-                gint            y,
-                GdkDragAction  *suggested_action,
-                GType          *target)
+set_destination (GtkIconView        *icon_view,
+                GtkDropTargetAsync *dest,
+                gint                x,
+                gint                y,
+                GdkDragAction      *suggested_action,
+                GType              *target)
 {
   GtkWidget *widget;
   GtkTreePath *path = NULL;
@@ -5863,7 +5861,7 @@ set_destination (GtkIconView    *icon_view,
       return FALSE; /* no longer a drop site */
     }
 
-  formats = gtk_drop_target_get_formats (dest);
+  formats = gtk_drop_target_async_get_formats (dest);
   *target = gdk_content_formats_match_gtype (formats, formats);
   if (*target == G_TYPE_INVALID)
     return FALSE;
@@ -6129,9 +6127,9 @@ gtk_icon_view_dnd_finished_cb (GdkDrag   *drag,
 
 /* Target side drag signals */
 static void
-gtk_icon_view_drag_leave (GtkDropTarget *dest,
-                          GdkDrop       *drop,
-                          GtkIconView   *icon_view)
+gtk_icon_view_drag_leave (GtkDropTargetAsync *dest,
+                          GdkDrop            *drop,
+                          GtkIconView        *icon_view)
 {
   /* unset any highlight row */
   gtk_icon_view_set_drag_dest_item (icon_view,
@@ -6141,24 +6139,22 @@ gtk_icon_view_drag_leave (GtkDropTarget *dest,
   remove_scroll_timeout (icon_view);
 }
 
-static void
-gtk_icon_view_drag_motion (GtkDropTarget *dest,
-                           GdkDrop       *drop,
-                          int            x,
-                          int            y,
-                           GtkIconView   *icon_view)
+static GdkDragAction
+gtk_icon_view_drag_motion (GtkDropTargetAsync *dest,
+                           GdkDrop            *drop,
+                          double              x,
+                          double              y,
+                           GtkIconView        *icon_view)
 {
   GtkTreePath *path = NULL;
   GtkIconViewDropPosition pos;
   GdkDragAction suggested_action = 0;
   GType target;
   gboolean empty;
+  GdkDragAction result;
 
   if (!set_destination (icon_view, dest, x, y, &suggested_action, &target))
-    {
-      gdk_drop_status (drop, 0);
-      return;
-    }
+    return 0;
 
   gtk_icon_view_get_drag_dest_item (icon_view, &path, &pos);
 
@@ -6168,7 +6164,7 @@ gtk_icon_view_drag_motion (GtkDropTarget *dest,
   if (path == NULL && !empty)
     {
       /* Can't drop here. */
-      gdk_drop_status (drop, 0);
+      result = 0;
     }
   else
     {
@@ -6189,20 +6185,22 @@ gtk_icon_view_drag_motion (GtkDropTarget *dest,
       else
         {
           set_status_pending (drop, 0);
-          gdk_drop_status (drop, suggested_action);
         }
+      result = suggested_action;
     }
 
   if (path)
     gtk_tree_path_free (path);
+
+  return result;
 }
 
 static gboolean 
-gtk_icon_view_drag_drop (GtkDropTarget *dest,
-                         GdkDrop       *drop,
-                        int            x,
-                        int            y,
-                         GtkIconView   *icon_view)
+gtk_icon_view_drag_drop (GtkDropTargetAsync *dest,
+                         GdkDrop            *drop,
+                        double              x,
+                        double              y,
+                         GtkIconView        *icon_view)
 {
   GtkTreePath *path;
   GdkDragAction suggested_action = 0;
@@ -6217,7 +6215,7 @@ gtk_icon_view_drag_drop (GtkDropTarget *dest,
   if (!icon_view->priv->dest_set)
     return FALSE;
 
-  if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag-drop"))
+  if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drop"))
     return FALSE;
 
   if (!set_destination (icon_view, dest, x, y, &suggested_action, &target))
@@ -6324,8 +6322,6 @@ gtk_icon_view_drag_data_received (GObject *source,
            suggested_action = 0;
         }
 
-      gdk_drop_status (drop, suggested_action);
-
       if (path)
         gtk_tree_path_free (path);
 
@@ -6407,10 +6403,11 @@ gtk_icon_view_enable_model_drag_dest (GtkIconView       *icon_view,
 
   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
 
-  icon_view->priv->dest = gtk_drop_target_new (gdk_content_formats_ref (formats), actions);
+  icon_view->priv->dest = gtk_drop_target_async_new (gdk_content_formats_ref (formats), actions);
   g_signal_connect (icon_view->priv->dest, "drag-leave", G_CALLBACK (gtk_icon_view_drag_leave), icon_view);
+  g_signal_connect (icon_view->priv->dest, "drag-enter", G_CALLBACK (gtk_icon_view_drag_motion), icon_view);
   g_signal_connect (icon_view->priv->dest, "drag-motion", G_CALLBACK (gtk_icon_view_drag_motion), icon_view);
-  g_signal_connect (icon_view->priv->dest, "drag-drop", G_CALLBACK (gtk_icon_view_drag_drop), icon_view);
+  g_signal_connect (icon_view->priv->dest, "drop", G_CALLBACK (gtk_icon_view_drag_drop), icon_view);
   gtk_widget_add_controller (GTK_WIDGET (icon_view), GTK_EVENT_CONTROLLER (icon_view->priv->dest));
 
   icon_view->priv->dest_actions = actions;
index c45c3ba3e90a6742ee4da98d019f95568c37968a..1cfd1aa3d87f42ca50e6a333fb667df9710f7a2f 100644 (file)
 
 #include "gtk/gtkiconview.h"
 #include "gtk/gtkcssnodeprivate.h"
-#include "gtk/gtkdragdest.h"
-#include "gtk/gtkgestureclick.h"
 #include "gtk/gtkeventcontrollermotion.h"
 #include "gtk/gtkdragsource.h"
+#include "gtk/gtkdroptargetasync.h"
+#include "gtk/gtkgestureclick.h"
 
 #ifndef __GTK_ICON_VIEW_PRIVATE_H__
 #define __GTK_ICON_VIEW_PRIVATE_H__
@@ -135,7 +135,7 @@ struct _GtkIconViewPrivate
   gint press_start_y;
 
   GdkContentFormats *source_formats;
-  GtkDropTarget *dest;
+  GtkDropTargetAsync *dest;
   GtkCssNode *dndnode;
 
   GdkDrag *drag;
index 9db8ee9ac0156ab957d43eb1813a6f72a06301b1..ffa4a0112cb2ee21037589b28304f10a35c58d79 100644 (file)
@@ -25,7 +25,6 @@
 #include "gtkbuildable.h"
 #include "gtkcontainerprivate.h"
 #include "gtkcssnodeprivate.h"
-#include "gtkdragdest.h"
 #include "gtkgestureclick.h"
 #include "gtkintl.h"
 #include "gtkmain.h"
index fe2f63812f57a277ebf9c81b161b1a883b2d8dd3..bc164008bb4daa33c208a94bf930caac1bbaef2f 100644 (file)
 #include "gtkaccelmapprivate.h"
 #include "gtkbox.h"
 #include "gtkdebug.h"
-#include "gtkdragdestprivate.h"
+#include "gtkdropprivate.h"
 #include "gtkmain.h"
 #include "gtkmediafileprivate.h"
 #include "gtkmodulesprivate.h"
@@ -1550,9 +1550,14 @@ handle_pointing_event (GdkEvent *event)
                                         event, gdk_crossing_event_get_mode (event), NULL);
       break;
     case GDK_DRAG_LEAVE:
-      old_target = update_pointer_focus_state (toplevel, event, NULL);
-      gtk_synthesize_crossing_events (GTK_ROOT (toplevel), GTK_CROSSING_DROP, old_target, NULL,
-                                      event, GDK_CROSSING_NORMAL, gdk_drag_event_get_drop (event));
+      {
+        GdkDrop *drop = gdk_drag_event_get_drop (event);
+        old_target = update_pointer_focus_state (toplevel, event, NULL);
+        gtk_drop_begin_event (drop, GDK_DRAG_LEAVE);
+        gtk_synthesize_crossing_events (GTK_ROOT (toplevel), GTK_CROSSING_DROP, old_target, NULL,
+                                        event, GDK_CROSSING_NORMAL, drop);
+        gtk_drop_end_event (drop);
+      }
       break;
     case GDK_ENTER_NOTIFY:
       if (gdk_crossing_event_get_mode (event) == GDK_CROSSING_GRAB ||
@@ -1586,10 +1591,14 @@ handle_pointing_event (GdkEvent *event)
 
           gtk_window_maybe_update_cursor (toplevel, NULL, device);
         }
-      else if (type == GDK_DRAG_ENTER || type == GDK_DRAG_MOTION || type == GDK_DROP_START)
+      else if ((old_target != target) &&
+               (type == GDK_DRAG_ENTER || type == GDK_DRAG_MOTION || type == GDK_DROP_START))
         {
+          GdkDrop *drop = gdk_drag_event_get_drop (event);
+          gtk_drop_begin_event (drop, type);
           gtk_synthesize_crossing_events (GTK_ROOT (toplevel), GTK_CROSSING_DROP, old_target, target,
                                           event, GDK_CROSSING_NORMAL, gdk_drag_event_get_drop (event));
+          gtk_drop_end_event (drop);
         }
       else if (type == GDK_TOUCH_BEGIN)
         gtk_window_set_pointer_focus_grab (toplevel, device, sequence, target);
@@ -1786,19 +1795,19 @@ gtk_main_do_event (GdkEvent *event)
 
     case GDK_ENTER_NOTIFY:
     case GDK_LEAVE_NOTIFY:
+    case GDK_DRAG_ENTER:
+    case GDK_DRAG_LEAVE:
       /* Crossing event propagation happens during picking */
       break;
 
     case GDK_DRAG_MOTION:
     case GDK_DROP_START:
-      if (gtk_propagate_event (target_widget, event))
-        break;
-      G_GNUC_FALLTHROUGH;
-
-    case GDK_DRAG_ENTER:
-    case GDK_DRAG_LEAVE:
-      /* Crossing event propagation happens during picking */
-      gtk_drag_dest_handle_event (target_widget, event);
+      {
+        GdkDrop *drop = gdk_drag_event_get_drop (event);
+        gtk_drop_begin_event (drop, gdk_event_get_event_type (event));
+        gtk_propagate_event (target_widget, event);
+        gtk_drop_end_event (drop);
+      }
       break;
 
     case GDK_EVENT_LAST:
index 7886f55dd73bdc5932c4f58dae0316e02b87f12d..92f7651a2e95aade97554fe70f1bf13dba04502f 100644 (file)
@@ -33,7 +33,7 @@
 #include "gtkbuildable.h"
 #include "gtkbutton.h"
 #include "gtkcssstylepropertyprivate.h"
-#include "gtkdragdest.h"
+#include "gtkdroptarget.h"
 #include "gtkdragicon.h"
 #include "gtkdropcontrollermotion.h"
 #include "gtkeventcontrollermotion.h"
@@ -793,14 +793,15 @@ static void gtk_notebook_dnd_finished_cb     (GdkDrag          *drag,
 static void gtk_notebook_drag_cancel_cb      (GdkDrag          *drag,
                                               GdkDragCancelReason reason,
                                               GtkWidget        *widget);
-static void     gtk_notebook_drag_motion     (GtkDropTarget    *dest,
-                                              GdkDrop          *drop,
-                                              int               x,
-                                              int               y);
+static GdkDragAction gtk_notebook_drag_motion(GtkDropTarget    *dest,
+                                              double            x,
+                                              double            y,
+                                              GtkNotebook      *notebook);
 static gboolean gtk_notebook_drag_drop       (GtkDropTarget    *dest,
-                                              GdkDrop          *drop,
-                                              int               x,
-                                              int               y);
+                                              const GValue     *value,
+                                              double            x,
+                                              double            y,
+                                              GtkNotebook      *notebook);
 
 /*** GtkContainer Methods ***/
 static void gtk_notebook_add                 (GtkContainer     *container,
@@ -1430,9 +1431,10 @@ gtk_notebook_init (GtkNotebook *notebook)
   gtk_widget_set_vexpand (priv->stack_widget, TRUE);
   gtk_widget_set_parent (priv->stack_widget, GTK_WIDGET (notebook));
 
-  dest = gtk_drop_target_new (gdk_content_formats_new_for_gtype (GTK_TYPE_NOTEBOOK_PAGE), GDK_ACTION_MOVE);
-  g_signal_connect (dest, "drag-motion", G_CALLBACK (gtk_notebook_drag_motion), NULL);
-  g_signal_connect (dest, "drag-drop", G_CALLBACK (gtk_notebook_drag_drop), NULL);
+  dest = gtk_drop_target_new (GTK_TYPE_NOTEBOOK_PAGE, GDK_ACTION_MOVE);
+  gtk_drop_target_set_preload (dest, TRUE);
+  g_signal_connect (dest, "motion", G_CALLBACK (gtk_notebook_drag_motion), notebook);
+  g_signal_connect (dest, "drop", G_CALLBACK (gtk_notebook_drag_drop), notebook);
   gtk_widget_add_controller (GTK_WIDGET (priv->tabs_widget), GTK_EVENT_CONTROLLER (dest));
 
   gesture = gtk_gesture_click_new ();
@@ -3294,112 +3296,78 @@ gtk_notebook_switch_page_timeout (gpointer data)
   return FALSE;
 }
 
-static void
-gtk_notebook_drag_motion (GtkDropTarget *dest,
-                          GdkDrop       *drop,
-                          int            x,
-                          int            y)
+static gboolean
+gtk_notebook_can_drag_from (GtkNotebook     *self,
+                            GtkNotebook     *other,
+                            GtkNotebookPage *page)
 {
-  GtkWidget *tabs = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (dest));
-  GtkWidget *widget = gtk_widget_get_ancestor (tabs, GTK_TYPE_NOTEBOOK);
-  GtkNotebook *notebook = GTK_NOTEBOOK (widget);
-  GtkNotebookPrivate *priv = notebook->priv;
-  GdkContentFormats *formats;
-
-  priv->mouse_x = x;
-  priv->mouse_y = y;
-
-  formats = gtk_drop_target_get_formats (dest);
-  if (gdk_content_formats_contain_gtype (formats, GTK_TYPE_NOTEBOOK_PAGE))
-    {
-      GQuark group, source_group;
-      GtkWidget *source_child;
-      GdkDrag *drag = gdk_drop_get_drag (drop);
-
-      if (!drag)
-        {
-          gdk_drop_status (drop, 0);
-        }
-      else
-        {
-          GtkNotebook *source = GTK_NOTEBOOK (g_object_get_data (G_OBJECT (drag), "gtk-notebook-drag-origin"));
+  /* always allow dragging inside self */
+  if (self == other)
+    return TRUE;
 
-          g_assert (source->priv->cur_page != NULL);
-          source_child = source->priv->cur_page->child;
+  /* if the groups don't match, fail */
+  if (self->priv->group == 0 ||
+      self->priv->group != other->priv->group)
+    return FALSE;
 
-          group = notebook->priv->group;
-          source_group = source->priv->group;
+  /* Check that the dragged page is not a parent of the notebook
+   * being dragged into */
+  if (GTK_WIDGET (self) == page->child ||
+      gtk_widget_is_ancestor (GTK_WIDGET (self), GTK_WIDGET (page->child)) ||
+      GTK_WIDGET (self) == page->tab_label ||
+      gtk_widget_is_ancestor (GTK_WIDGET (self), GTK_WIDGET (page->tab_label)))
+    return FALSE;
 
-          if (group != 0 && group == source_group &&
-              !(widget == source_child ||
-              gtk_widget_is_ancestor (widget, source_child)))
-            {
-              gdk_drop_status (drop, GDK_ACTION_MOVE);
-            }
-          else
-            {
-              /* it's a tab, but doesn't share
-               * ID with this notebook */
-              gdk_drop_status (drop, 0);
-            }
-        }
-    }
+  return TRUE;
 }
 
-static void
-got_page (GObject      *source,
-          GAsyncResult *result,
-          gpointer      data)
+static GdkDragAction
+gtk_notebook_drag_motion (GtkDropTarget *dest,
+                          double         x,
+                          double         y,
+                          GtkNotebook   *notebook)
 {
-  GtkNotebook *notebook = GTK_NOTEBOOK (data);
-  GdkDrop *drop = GDK_DROP (source);
-  GdkDrag *drag = gdk_drop_get_drag (drop);
-  GtkWidget *source_widget;
-  const GValue *value;
+  GtkNotebookPrivate *priv = notebook->priv;
+  GdkDrag *drag = gdk_drop_get_drag (gtk_drop_target_get_drop (dest));
+  GtkNotebook *source;
 
-  source_widget = GTK_WIDGET (drag ? g_object_get_data (G_OBJECT (drag), "gtk-notebook-drag-origin") : NULL);
+  priv->mouse_x = x;
+  priv->mouse_y = y;
 
-  value = gdk_drop_read_value_finish (drop, result, NULL);
+  if (!drag)
+    return 0;
 
-  if (value)
-    {
-      GtkNotebookPage *page = g_value_get_object (value);
+  source = GTK_NOTEBOOK (g_object_get_data (G_OBJECT (drag), "gtk-notebook-drag-origin"));
+  g_assert (source->priv->cur_page != NULL);
 
-      do_detach_tab (GTK_NOTEBOOK (source_widget), notebook, page->child);
-      gdk_drop_finish (drop, GDK_ACTION_MOVE);
-    }
-  else
-    gdk_drop_finish (drop, 0);
+  if (!gtk_notebook_can_drag_from (notebook, source, source->priv->cur_page))
+    return 0;
+
+  return GDK_ACTION_MOVE;
 }
 
 static gboolean
 gtk_notebook_drag_drop (GtkDropTarget *dest,
-                        GdkDrop       *drop,
-                        int            x,
-                        int            y)
+                        const GValue  *value,
+                        double         x,
+                        double         y,
+                        GtkNotebook   *self)
 {
-  GtkWidget *tabs = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (dest));
-  GtkWidget *widget = gtk_widget_get_ancestor (tabs, GTK_TYPE_NOTEBOOK);
-  GtkNotebook *notebook = GTK_NOTEBOOK (widget);
-  GdkDrag *drag = gdk_drop_get_drag (drop);
-  GtkWidget *source_widget;
+  GdkDrag *drag = gdk_drop_get_drag (gtk_drop_target_get_drop (dest));
+  GtkNotebook *source;
+  GtkNotebookPage *page = g_value_get_object (value);
 
-  source_widget = GTK_WIDGET (drag ? g_object_get_data (G_OBJECT (drag), "gtk-notebook-drag-origin") : NULL);
-
-  if (GTK_IS_NOTEBOOK (source_widget) &&
-      (gdk_drop_get_actions (drop) & GDK_ACTION_MOVE))
-    {
-      notebook->priv->mouse_x = x;
-      notebook->priv->mouse_y = y;
+  source = drag ? g_object_get_data (G_OBJECT (drag), "gtk-notebook-drag-origin") : NULL;
 
-      gdk_drop_read_value_async (drop, GTK_TYPE_NOTEBOOK_PAGE, G_PRIORITY_DEFAULT, NULL, got_page, notebook);
+  if (!gtk_notebook_can_drag_from (self, source, source->priv->cur_page))
+    return FALSE;
 
-      return TRUE;
-    }
+  self->priv->mouse_x = x;
+  self->priv->mouse_y = y;
 
-  gdk_drop_finish (drop, 0);
+  do_detach_tab (source, self, page->child);
 
-  return FALSE;
+  return TRUE;
 }
 
 /**
index 925370a6a4563179c036fd7af44e2a16d6053bd9..f62569b5f63de0b614110e482dd58c9086b699d7 100644 (file)
@@ -50,7 +50,7 @@
 #include "gtklabel.h"
 #include "gtkbutton.h"
 #include "gtklistbox.h"
-#include "gtkdragdest.h"
+#include "gtkdroptarget.h"
 #include "gtkseparator.h"
 #include "gtkentry.h"
 #include "gtkgesturelongpress.h"
@@ -150,8 +150,6 @@ struct _GtkPlacesSidebar {
   GtkWidget *trash_row;
 
   /* DND */
-  GSList    *drag_list; /* list of GFile */
-  gint       drag_data_info;
   gboolean   dragging_over;
   GtkWidget *drag_row;
   gint drag_row_height;
@@ -175,8 +173,6 @@ struct _GtkPlacesSidebar {
   GtkPlacesOpenFlags open_flags;
 
   guint mounting               : 1;
-  guint  drag_data_received    : 1;
-  guint drop_occurred          : 1;
   guint show_recent_set        : 1;
   guint show_recent            : 1;
   guint show_desktop_set       : 1;
@@ -300,13 +296,6 @@ static GMountOperation * get_mount_operation (GtkPlacesSidebar *sidebar);
 static GMountOperation * get_unmount_operation (GtkPlacesSidebar *sidebar);
 
 
-/* Identifiers for target types */
-enum {
-  DND_UNKNOWN,
-  DND_GTK_SIDEBAR_ROW,
-  DND_TEXT_URI_LIST
-};
-
 G_DEFINE_TYPE (GtkPlacesSidebar, gtk_places_sidebar, GTK_TYPE_WIDGET);
 
 static void
@@ -380,18 +369,6 @@ emit_drag_action_requested (GtkPlacesSidebar *sidebar,
   return ret_action;
 }
 
-static GdkDragAction
-emit_drag_action_ask (GtkPlacesSidebar *sidebar,
-                      GdkDragAction     actions)
-{
-  GdkDragAction ret_action = 0;
-
-  g_signal_emit (sidebar, places_sidebar_signals[DRAG_ACTION_ASK], 0,
-                 actions, &ret_action);
-
-  return ret_action;
-}
-
 static void
 emit_drag_perform_drop (GtkPlacesSidebar *sidebar,
                         GFile            *dest_file,
@@ -1513,7 +1490,8 @@ update_places (GtkPlacesSidebar *sidebar)
 
 static gboolean
 check_valid_drop_target (GtkPlacesSidebar *sidebar,
-                         GtkSidebarRow    *row)
+                         GtkSidebarRow    *row,
+                         const GValue     *value)
 {
   GtkPlacesSidebarPlaceType place_type;
   GtkPlacesSidebarSectionType section_type;
@@ -1522,6 +1500,8 @@ check_valid_drop_target (GtkPlacesSidebar *sidebar,
   GFile *dest_file;
   gint drag_action;
 
+  g_return_val_if_fail (value != NULL, TRUE);
+
   if (row == NULL)
     return FALSE;
 
@@ -1560,19 +1540,18 @@ check_valid_drop_target (GtkPlacesSidebar *sidebar,
     }
 
   /* Dragging a bookmark? */
-  if (sidebar->drag_data_received &&
-      sidebar->drag_data_info == DND_GTK_SIDEBAR_ROW)
+  if (G_VALUE_HOLDS (value, GTK_TYPE_SIDEBAR_ROW))
     {
       /* Don't allow reordering bookmarks into non-bookmark areas */
       valid = section_type == SECTION_BOOKMARKS;
     }
-  else
+  else if (G_VALUE_HOLDS (value, GDK_TYPE_FILE_LIST))
     {
       /* Dragging a file */
       if (uri != NULL)
         {
           dest_file = g_file_new_for_uri (uri);
-          drag_action = emit_drag_action_requested (sidebar, dest_file, sidebar->drag_list);
+          drag_action = emit_drag_action_requested (sidebar, dest_file, g_value_get_boxed (value));
           valid = drag_action > 0;
 
           g_object_unref (dest_file);
@@ -1582,6 +1561,11 @@ check_valid_drop_target (GtkPlacesSidebar *sidebar,
           valid = FALSE;
         }
     }
+  else
+    {
+      g_assert_not_reached ();
+      valid = TRUE;
+    }
 
   g_free (uri);
   return valid;
@@ -1589,7 +1573,7 @@ check_valid_drop_target (GtkPlacesSidebar *sidebar,
 
 static void
 update_possible_drop_targets (GtkPlacesSidebar *sidebar,
-                              gboolean          dragging)
+                              const GValue     *value)
 {
   GList *rows;
   GList *l;
@@ -1599,55 +1583,18 @@ update_possible_drop_targets (GtkPlacesSidebar *sidebar,
 
   for (l = rows; l != NULL; l = l->next)
     {
-      sensitive = !dragging || check_valid_drop_target (sidebar, GTK_SIDEBAR_ROW (l->data));
+      sensitive = value == NULL || check_valid_drop_target (sidebar, GTK_SIDEBAR_ROW (l->data), value);
       gtk_widget_set_sensitive (GTK_WIDGET (l->data), sensitive);
     }
 
   g_list_free (rows);
 }
 
-static void drag_data_received_callback (GObject      *source,
-                                         GAsyncResult *result,
-                                         gpointer      user_data);
-
-static gboolean
-get_drag_data (GtkPlacesSidebar *self,
-               GtkDropTarget    *dest,
-               GdkDrop          *drop,
-               GtkListBoxRow    *row)
-{
-  GdkContentFormats *formats = gdk_drop_get_formats (drop);
-
-  if (row)
-    g_object_set_data_full (G_OBJECT (drop), "places-sidebar-row", g_object_ref (row), g_object_unref);
-
-  gdk_drop_read_value_async (drop,
-                             gdk_content_formats_match_gtype (formats, formats),
-                             G_PRIORITY_DEFAULT,
-                             NULL,
-                             drag_data_received_callback,
-                             self->list_box);
-
-  return TRUE;
-}
-
 static void
-free_drag_data (GtkPlacesSidebar *sidebar)
+start_drop_feedback (GtkPlacesSidebar *sidebar,
+                     const GValue     *value)
 {
-  sidebar->drag_data_received = FALSE;
-
-  if (sidebar->drag_list)
-    {
-      g_slist_free_full (sidebar->drag_list, g_object_unref);
-      sidebar->drag_list = NULL;
-    }
-}
-
-static void
-start_drop_feedback (GtkPlacesSidebar *sidebar)
-{
-  if (sidebar->drag_data_received &&
-      sidebar->drag_data_info != DND_GTK_SIDEBAR_ROW)
+  if (value && !G_VALUE_HOLDS (value, GTK_TYPE_SIDEBAR_ROW))
     {
       gtk_sidebar_row_reveal (GTK_SIDEBAR_ROW (sidebar->new_bookmark_row));
       /* If the state is permanent, don't change it. The application controls it. */
@@ -1655,15 +1602,13 @@ start_drop_feedback (GtkPlacesSidebar *sidebar)
         sidebar->drop_state = DROP_STATE_NEW_BOOKMARK_ARMED;
     }
 
-  update_possible_drop_targets (sidebar, TRUE);
+  update_possible_drop_targets (sidebar, value);
 }
 
 static void
 stop_drop_feedback (GtkPlacesSidebar *sidebar)
 {
-  update_possible_drop_targets (sidebar, FALSE);
-
-  free_drag_data (sidebar);
+  update_possible_drop_targets (sidebar, NULL);
 
   if (sidebar->drop_state != DROP_STATE_NEW_BOOKMARK_ARMED_PERMANENT &&
       sidebar->new_bookmark_row != NULL)
@@ -1686,7 +1631,6 @@ stop_drop_feedback (GtkPlacesSidebar *sidebar)
     }
 
   sidebar->dragging_over = FALSE;
-  sidebar->drag_data_info = DND_UNKNOWN;
 }
 
 static GtkWidget *
@@ -1695,20 +1639,19 @@ create_placeholder_row (GtkPlacesSidebar *sidebar)
   return g_object_new (GTK_TYPE_SIDEBAR_ROW, "placeholder", TRUE, NULL);
 }
 
-static void
-drag_motion_callback (GtkDropTarget *dest,
-                      GdkDrop       *drop,
-                      gint           x,
-                      gint           y,
-                      gpointer       user_data)
+static GdkDragAction
+drag_motion_callback (GtkDropTarget    *target,
+                      double            x,
+                      double            y,
+                      GtkPlacesSidebar *sidebar)
 {
-  GtkPlacesSidebar *sidebar = GTK_PLACES_SIDEBAR (user_data);
-  gint action;
+  GdkDragAction action;
   GtkListBoxRow *row;
   GtkPlacesSidebarPlaceType place_type;
   gchar *drop_target_uri = NULL;
   gint row_index;
   gint row_placeholder_index;
+  const GValue *value;
 
   sidebar->dragging_over = TRUE;
   action = 0;
@@ -1716,17 +1659,16 @@ drag_motion_callback (GtkDropTarget *dest,
 
   gtk_list_box_drag_unhighlight_row (GTK_LIST_BOX (sidebar->list_box));
 
-  /* Nothing to do if no drag data */
-  if (!sidebar->drag_data_received &&
-      !get_drag_data (sidebar, dest, drop, row))
+  /* Nothing to do if no value yet */
+  value = gtk_drop_target_get_value (target);
+  if (value == NULL)
     goto out;
 
   /* Nothing to do if the target is not valid drop destination */
-  if (!check_valid_drop_target (sidebar, GTK_SIDEBAR_ROW (row)))
+  if (!check_valid_drop_target (sidebar, GTK_SIDEBAR_ROW (row), value))
     goto out;
 
-  if (sidebar->drag_data_received &&
-      sidebar->drag_data_info == DND_GTK_SIDEBAR_ROW)
+  if (G_VALUE_HOLDS (value, GTK_TYPE_SIDEBAR_ROW))
     {
       /* Dragging bookmarks always moves them to another position in the bookmarks list */
       action = GDK_ACTION_MOVE;
@@ -1783,7 +1725,7 @@ drag_motion_callback (GtkDropTarget *dest,
       gtk_list_box_prepend (GTK_LIST_BOX (sidebar->list_box),
                             sidebar->row_placeholder);
     }
-  else
+  else if (G_VALUE_HOLDS (value, GDK_TYPE_FILE_LIST))
     {
       gtk_list_box_drag_highlight_row (GTK_LIST_BOX (sidebar->list_box), row);
 
@@ -1795,32 +1737,33 @@ drag_motion_callback (GtkDropTarget *dest,
        * file move/copy operation itself, or if we should only try to
        * create bookmarks out of the dragged URIs.
        */
-      if (sidebar->drag_list != NULL)
+      if (place_type == PLACES_DROP_FEEDBACK)
         {
-          if (place_type == PLACES_DROP_FEEDBACK)
-            {
-              action = GDK_ACTION_COPY;
-            }
-          else
+          action = GDK_ACTION_COPY;
+        }
+      else
+        {
+          /* uri may be NULL for unmounted volumes, for example, so we don't allow drops there */
+          if (drop_target_uri != NULL)
             {
-              /* uri may be NULL for unmounted volumes, for example, so we don't allow drops there */
-              if (drop_target_uri != NULL)
-                {
-                  GFile *dest_file = g_file_new_for_uri (drop_target_uri);
+              GFile *dest_file = g_file_new_for_uri (drop_target_uri);
 
-                  action = emit_drag_action_requested (sidebar, dest_file, sidebar->drag_list);
+              action = emit_drag_action_requested (sidebar, dest_file, g_value_get_boxed (value));
 
-                  g_object_unref (dest_file);
-                }
+              g_object_unref (dest_file);
             }
         }
 
       g_free (drop_target_uri);
     }
+  else
+    {
+      g_assert_not_reached ();
+    }
 
  out:
-  start_drop_feedback (sidebar);
-  gdk_drop_status (drop, action);
+  start_drop_feedback (sidebar, value);
+  return action;
 }
 
 /* Reorders the bookmark to the specified position */
@@ -1867,51 +1810,26 @@ drop_files_as_bookmarks (GtkPlacesSidebar *sidebar,
     }
 }
 
-static void
-drag_data_received_callback (GObject      *source,
-                             GAsyncResult *result,
-                             gpointer      user_data)
+static gboolean
+drag_drop_callback (GtkDropTarget    *target,
+                    const GValue     *value,
+                    double            x,
+                    double            y,
+                    GtkPlacesSidebar *sidebar)
 {
-  GdkDrop *drop = GDK_DROP (source);
-  GtkWidget *list_box = user_data;
-  GtkPlacesSidebar *sidebar = GTK_PLACES_SIDEBAR (gtk_widget_get_ancestor (list_box, GTK_TYPE_PLACES_SIDEBAR));
   gint target_order_index;
   GtkPlacesSidebarPlaceType target_place_type;
   GtkPlacesSidebarSectionType target_section_type;
   gchar *target_uri;
   GtkListBoxRow *target_row;
-  GdkDragAction real_action;
-  const GValue *value;
-
-  value = gdk_drop_read_value_finish (drop, result, NULL);
-
-  if (!sidebar->drag_data_received)
-    {
-      if (G_VALUE_HOLDS (value, GDK_TYPE_FILE_LIST))
-        {
-          /* Free spurious drag data from previous drags if present */
-          if (sidebar->drag_list != NULL)
-            g_slist_free_full (sidebar->drag_list, g_object_unref);
-          sidebar->drag_list = g_slist_copy_deep (g_value_get_boxed (value), (GCopyFunc) g_object_ref, NULL);
-          sidebar->drag_data_info = DND_TEXT_URI_LIST;
-        }
-      else if (G_VALUE_HOLDS (value, GTK_TYPE_SIDEBAR_ROW))
-        {
-          sidebar->drag_list = NULL;
-          sidebar->drag_data_info = DND_GTK_SIDEBAR_ROW;
-        }
-      sidebar->drag_data_received = TRUE;
-    }
+  gboolean result;
 
-  if (!sidebar->drop_occurred)
-    return;
-
-  target_row = g_object_get_data (G_OBJECT (drop), "places-sidebar-row");
+  target_row = gtk_list_box_get_row_at_y (GTK_LIST_BOX (sidebar->list_box), y);
   if (target_row == NULL)
-    return;
+    return FALSE;
 
-  if (!check_valid_drop_target (sidebar, GTK_SIDEBAR_ROW (target_row)))
-    return;
+  if (!check_valid_drop_target (sidebar, GTK_SIDEBAR_ROW (target_row), value))
+    return FALSE;
 
   g_object_get (target_row,
                 "place-type", &target_place_type,
@@ -1919,9 +1837,9 @@ drag_data_received_callback (GObject      *source,
                 "order-index", &target_order_index,
                 "uri", &target_uri,
                 NULL);
-  real_action = 0;
+  result = FALSE;
 
-  if (sidebar->drag_data_info == DND_GTK_SIDEBAR_ROW)
+  if (G_VALUE_HOLDS (value, GTK_TYPE_SIDEBAR_ROW))
     {
       GtkWidget **source_row;
       /* A bookmark got reordered */
@@ -1934,41 +1852,37 @@ drag_data_received_callback (GObject      *source,
         g_object_get (sidebar->row_placeholder, "order-index", &target_order_index, NULL);
 
       reorder_bookmarks (sidebar, GTK_SIDEBAR_ROW (*source_row), target_order_index);
-      real_action = GDK_ACTION_MOVE;
+      result = TRUE;
     }
-  else
+  else if (G_VALUE_HOLDS (value, GDK_TYPE_FILE_LIST))
     {
       /* Dropping URIs! */
-
-      /* file transfer requested */
-      real_action = gdk_drop_get_actions (drop);
-
-      if (!gdk_drag_action_is_unique (real_action))
-        real_action = emit_drag_action_ask (sidebar, real_action);
-
-      if (real_action > 0)
+      if (target_place_type == PLACES_DROP_FEEDBACK)
         {
-          if (target_place_type == PLACES_DROP_FEEDBACK)
-            {
-              drop_files_as_bookmarks (sidebar, sidebar->drag_list, target_order_index);
-            }
-          else
-            {
-              GFile *dest_file = g_file_new_for_uri (target_uri);
-
-              emit_drag_perform_drop (sidebar, dest_file, sidebar->drag_list, real_action);
+          drop_files_as_bookmarks (sidebar, g_value_get_boxed (value), target_order_index);
+        }
+      else
+        {
+          GFile *dest_file = g_file_new_for_uri (target_uri);
+          
+          emit_drag_perform_drop (sidebar,
+                                  dest_file,
+                                  g_value_get_boxed (value),
+                                  gdk_drop_get_actions (gtk_drop_target_get_drop (target)));
 
-              g_object_unref (dest_file);
-            }
+          g_object_unref (dest_file);
         }
+      result = TRUE;
+    }
+  else
+    {
+      g_assert_not_reached ();
     }
 
 out:
-  sidebar->drop_occurred = FALSE;
-  g_object_set_data (G_OBJECT (drop), "places-sidebar-row", NULL);
-  gdk_drop_finish (drop, real_action);
   stop_drop_feedback (sidebar);
   g_free (target_uri);
+  return result;
 }
 
 static void
@@ -2010,28 +1924,7 @@ drag_leave_callback (GtkDropTarget *dest,
       sidebar->drop_state = DROP_STATE_NORMAL;
     }
 
-  sidebar->drag_data_received = FALSE;
   sidebar->dragging_over = FALSE;
-  sidebar->drag_data_info = DND_UNKNOWN;
-}
-
-static gboolean
-drag_drop_callback (GtkDropTarget *dest,
-                    GdkDrop       *drop,
-                    int            x,
-                    int            y,
-                    gpointer       user_data)
-{
-  GtkPlacesSidebar *sidebar = GTK_PLACES_SIDEBAR (user_data);
-  gboolean retval = FALSE;
-  GtkListBoxRow *row;
-
-  row = gtk_list_box_get_row_at_y (GTK_LIST_BOX (sidebar->list_box), y);
-  sidebar->drop_occurred = TRUE;
-  retval = get_drag_data (sidebar, dest, drop, row);
-
-  return retval;
 }
 
 static void
@@ -3842,11 +3735,10 @@ shell_shows_desktop_changed (GtkSettings *settings,
 static void
 gtk_places_sidebar_init (GtkPlacesSidebar *sidebar)
 {
-  GtkDropTarget *dest;
+  GtkDropTarget *target;
   gboolean show_desktop;
   GtkEventController *controller;
   GtkGesture *gesture;
-  GdkContentFormatsBuilder *builder;
 
   sidebar->cancellable = g_cancellable_new ();
 
@@ -3901,20 +3793,18 @@ gtk_places_sidebar_init (GtkPlacesSidebar *sidebar)
   gtk_widget_add_controller (GTK_WIDGET (sidebar), GTK_EVENT_CONTROLLER (gesture));
 
   /* DND support */
-  builder = gdk_content_formats_builder_new ();
-  gdk_content_formats_builder_add_gtype (builder, GTK_TYPE_SIDEBAR_ROW);
-  gdk_content_formats_builder_add_gtype (builder, GDK_TYPE_FILE_LIST);
-  dest = gtk_drop_target_new (gdk_content_formats_builder_free_to_formats (builder),
-                              GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_LINK);
-  g_signal_connect (dest, "drag-motion", G_CALLBACK (drag_motion_callback), sidebar);
-  g_signal_connect (dest, "drag-drop", G_CALLBACK (drag_drop_callback), sidebar);
-  g_signal_connect (dest, "drag-leave", G_CALLBACK (drag_leave_callback), sidebar);
-  gtk_widget_add_controller (sidebar->list_box, GTK_EVENT_CONTROLLER (dest));
+  target = gtk_drop_target_new (G_TYPE_INVALID, GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_LINK);
+  gtk_drop_target_set_preload (target, TRUE);
+  gtk_drop_target_set_gtypes (target, (GType[2]) { GTK_TYPE_SIDEBAR_ROW, GDK_TYPE_FILE_LIST }, 2);
+  g_signal_connect (target, "enter", G_CALLBACK (drag_motion_callback), sidebar);
+  g_signal_connect (target, "motion", G_CALLBACK (drag_motion_callback), sidebar);
+  g_signal_connect (target, "drop", G_CALLBACK (drag_drop_callback), sidebar);
+  g_signal_connect (target, "leave", G_CALLBACK (drag_leave_callback), sidebar);
+  gtk_widget_add_controller (sidebar->list_box, GTK_EVENT_CONTROLLER (target));
 
   sidebar->drag_row = NULL;
   sidebar->row_placeholder = NULL;
   sidebar->dragging_over = FALSE;
-  sidebar->drag_data_info = DND_UNKNOWN;
 
   gtk_container_add (GTK_CONTAINER (sidebar->swin), sidebar->list_box);
 
@@ -4071,8 +3961,6 @@ gtk_places_sidebar_dispose (GObject *object)
       sidebar->cancellable = NULL;
     }
 
-  free_drag_data (sidebar);
-
   if (sidebar->bookmarks_manager != NULL)
     {
       _gtk_bookmarks_manager_free (sidebar->bookmarks_manager);
@@ -5068,7 +4956,7 @@ gtk_places_sidebar_set_drop_targets_visible (GtkPlacesSidebar *sidebar,
   if (visible)
     {
       sidebar->drop_state = DROP_STATE_NEW_BOOKMARK_ARMED_PERMANENT;
-      start_drop_feedback (sidebar);
+      start_drop_feedback (sidebar, NULL);
     }
   else
     {
index 56f748d3125f1b9f708e7aa9aa7503f56e09c3fd..52af78a2116da02d2da122e9e9d42508b9e0afd0 100644 (file)
@@ -30,6 +30,9 @@
 #include "gtkbutton.h"
 #include "gtkcssnodeprivate.h"
 #include "gtkdebug.h"
+#include "gtkdragicon.h"
+#include "gtkdragsource.h"
+#include "gtkdroptarget.h"
 #include "gtkeditable.h"
 #include "gtkemojichooser.h"
 #include "gtkemojicompletion.h"
@@ -65,9 +68,6 @@
 #include "gtkwindow.h"
 #include "gtknative.h"
 #include "gtkactionmuxerprivate.h"
-#include "gtkdragsource.h"
-#include "gtkdragdest.h"
-#include "gtkdragicon.h"
 
 #include "a11y/gtktextaccessible.h"
 
@@ -190,7 +190,6 @@ struct _GtkTextPrivate
   int           dnd_position;               /* In chars, -1 == no DND cursor */
   int           drag_start_x;
   int           drag_start_y;
-  int           drop_position;              /* where the drop should happen */
   int           insert_pos;
   int           selection_bound;
   int           scroll_offset;
@@ -336,20 +335,18 @@ static void   gtk_text_state_flags_changed  (GtkWidget        *widget,
 static void   gtk_text_root                 (GtkWidget        *widget);
 
 static gboolean gtk_text_drag_drop          (GtkDropTarget    *dest,
-                                             GdkDrop          *drop,
-                                             int               x,
-                                             int               y,
+                                             const GValue     *value,
+                                             double            x,
+                                             double            y,
                                              GtkText          *text);
 static gboolean gtk_text_drag_accept        (GtkDropTarget    *dest,
                                              GdkDrop          *drop,
                                              GtkText          *self);
-static void     gtk_text_drag_motion        (GtkDropTarget    *dest,
-                                             GdkDrop          *drop,
-                                             int               x,
-                                             int               y,
+static GdkDragAction gtk_text_drag_motion   (GtkDropTarget    *dest,
+                                             double            x,
+                                             double            y,
                                              GtkText          *text);
 static void     gtk_text_drag_leave         (GtkDropTarget    *dest,
-                                             GdkDrop          *drop,
                                              GtkText          *text);
 
 
@@ -1712,7 +1709,7 @@ gtk_text_init (GtkText *self)
   GtkGesture *gesture;
   GtkEventController *controller;
   int i;
-  GtkDropTarget *dest;
+  GtkDropTarget *target;
 
   gtk_widget_set_can_focus (GTK_WIDGET (self), TRUE);
   gtk_widget_set_overflow (GTK_WIDGET (self), GTK_OVERFLOW_HIDDEN);
@@ -1734,13 +1731,13 @@ gtk_text_init (GtkText *self)
   priv->selection_content = g_object_new (GTK_TYPE_TEXT_CONTENT, NULL);
   GTK_TEXT_CONTENT (priv->selection_content)->self = self;
 
-  dest = gtk_drop_target_new (gdk_content_formats_new_for_gtype (G_TYPE_STRING),
-                              GDK_ACTION_COPY | GDK_ACTION_MOVE);
-  g_signal_connect (dest, "accept", G_CALLBACK (gtk_text_drag_accept), self);
-  g_signal_connect (dest, "drag-motion", G_CALLBACK (gtk_text_drag_motion), self);
-  g_signal_connect (dest, "drag-leave", G_CALLBACK (gtk_text_drag_leave), self);
-  g_signal_connect (dest, "drag-drop", G_CALLBACK (gtk_text_drag_drop), self);
-  gtk_widget_add_controller (GTK_WIDGET (self), GTK_EVENT_CONTROLLER (dest));
+  target = gtk_drop_target_new (G_TYPE_STRING, GDK_ACTION_COPY | GDK_ACTION_MOVE);
+  g_signal_connect (target, "accept", G_CALLBACK (gtk_text_drag_accept), self);
+  g_signal_connect (target, "enter", G_CALLBACK (gtk_text_drag_motion), self);
+  g_signal_connect (target, "motion", G_CALLBACK (gtk_text_drag_motion), self);
+  g_signal_connect (target, "leave", G_CALLBACK (gtk_text_drag_leave), self);
+  g_signal_connect (target, "drop", G_CALLBACK (gtk_text_drag_drop), self);
+  gtk_widget_add_controller (GTK_WIDGET (self), GTK_EVENT_CONTROLLER (target));
 
   /* This object is completely private. No external entity can gain a reference
    * to it; so we create it here and destroy it in finalize().
@@ -6120,8 +6117,7 @@ gtk_text_selection_bubble_popup_set (GtkText *self)
 
 static void
 gtk_text_drag_leave (GtkDropTarget *dest,
-                     GdkDrop       *drop,
-                     GtkText *self)
+                     GtkText       *self)
 {
   GtkTextPrivate *priv = gtk_text_get_instance_private (self);
   GtkWidget *widget = GTK_WIDGET (self);
@@ -6130,94 +6126,45 @@ gtk_text_drag_leave (GtkDropTarget *dest,
   gtk_widget_queue_draw (widget);
 }
 
-static GdkDragAction
-gtk_text_get_action (GtkText *self,
-                     GdkDrop *drop)
+static gboolean
+gtk_text_drag_drop (GtkDropTarget *dest,
+                    const GValue  *value,
+                    double         x,
+                    double         y,
+                    GtkText       *self)
 {
   GtkTextPrivate *priv = gtk_text_get_instance_private (self);
-  GdkDrag *drag = gdk_drop_get_drag (drop);
-  GdkDragAction actions;
-
-  actions = gdk_drop_get_actions (drop);
-
-  if (drag == priv->drag &&
-      actions & GDK_ACTION_MOVE)
-    return GDK_ACTION_MOVE;
-
-  if (actions & GDK_ACTION_COPY)
-    return GDK_ACTION_COPY;
-
-  if (actions & GDK_ACTION_MOVE)
-    return GDK_ACTION_MOVE;
+  int drop_position;
+  int length;
+  const char *str;
 
-  return 0;
-}
+  if (!priv->editable)
+    return FALSE;
 
-static void
-got_text (GObject      *source,
-          GAsyncResult *result,
-          gpointer      data)
-{
-  GdkDrop *drop = GDK_DROP (source);
-  GtkText *self = GTK_TEXT (data);
-  GtkTextPrivate *priv = gtk_text_get_instance_private (self);
-  char *str;
-  GdkDragAction action;
+  drop_position = gtk_text_find_position (self, x + priv->scroll_offset);
 
-  str = gdk_drop_read_text_finish (drop, result, NULL);
-  action = gtk_text_get_action (self, drop);
+  str = g_value_get_string (value);
+  if (priv->truncate_multiline)
+    length = truncate_multiline (str);
+  else
+    length = -1;
 
-  if (action && str)
+  if (priv->selection_bound == priv->current_pos ||
+      drop_position < priv->selection_bound ||
+      drop_position > priv->current_pos)
     {
-      int length = -1;
-      int pos;
-
-      if (priv->truncate_multiline)
-        length = truncate_multiline (str);
-
-      if (priv->selection_bound == priv->current_pos ||
-          priv->drop_position < priv->selection_bound ||
-          priv->drop_position > priv->current_pos)
-        {
-          gtk_text_insert_text (self, str, length, &priv->drop_position);
-        }
-      else
-        {
-          /* Replacing selection */
-          begin_change (self);
-          gtk_text_delete_selection (self);
-          pos = MIN (priv->selection_bound, priv->current_pos);
-          gtk_text_insert_text (self, str, length, &pos);
-          end_change (self);
-        }
-      
-      gdk_drop_finish (drop, action);
+      gtk_text_insert_text (self, str, length, &drop_position);
     }
   else
     {
-      /* Drag and drop didn't happen! */
-      gdk_drop_finish (drop, 0);
-    }
-
-  g_free (str);
-}
-
-static gboolean
-gtk_text_drag_drop (GtkDropTarget *dest,
-                    GdkDrop       *drop,
-                    int            x,
-                    int            y,
-                    GtkText       *self)
-{
-  GtkTextPrivate *priv = gtk_text_get_instance_private (self);
-
-  if (priv->editable && gdk_drop_has_value (drop, G_TYPE_STRING))
-    {
-      priv->drop_position = gtk_text_find_position (self, x + priv->scroll_offset);
-      gdk_drop_read_text_async (drop, NULL, got_text, self);
+      int pos;
+      /* Replacing selection */
+      begin_change (self);
+      gtk_text_delete_selection (self);
+      pos = MIN (priv->selection_bound, priv->current_pos);
+      gtk_text_insert_text (self, str, length, &pos);
+      end_change (self);
     }
-  else
-    gdk_drop_finish (drop, 0);
   
   return TRUE;
 }
@@ -6238,40 +6185,42 @@ gtk_text_drag_accept (GtkDropTarget *dest,
   return gdk_content_formats_match (gtk_drop_target_get_formats (dest), gdk_drop_get_formats (drop));
 }
 
-static void
-gtk_text_drag_motion (GtkDropTarget *dest,
-                      GdkDrop       *drop,
-                      int            x,
-                      int            y,
-                      GtkText        *self)
+static GdkDragAction
+gtk_text_drag_motion (GtkDropTarget *target,
+                      double         x,
+                      double         y,
+                      GtkText       *self)
 {
   GtkTextPrivate *priv = gtk_text_get_instance_private (self);
   int new_position, old_position;
 
+  if (!priv->editable)
+    {
+      gtk_drop_target_reject (target);
+      return 0;
+    }
+
   old_position = priv->dnd_position;
   new_position = gtk_text_find_position (self, x + priv->scroll_offset);
 
-  if (priv->editable)
+  if (priv->selection_bound == priv->current_pos ||
+      new_position < priv->selection_bound ||
+      new_position > priv->current_pos)
     {
-      if (priv->selection_bound == priv->current_pos ||
-          new_position < priv->selection_bound ||
-          new_position > priv->current_pos)
-        {
-          priv->dnd_position = new_position;
-        }
-      else
-        {
-          priv->dnd_position = -1;
-        }
+      priv->dnd_position = new_position;
     }
   else
     {
-      /* Entry not editable, or no text */
       priv->dnd_position = -1;
     }
 
   if (priv->dnd_position != old_position)
     gtk_widget_queue_draw (GTK_WIDGET (self));
+
+  if (priv->drag)
+    return GDK_ACTION_MOVE;
+  else
+    return GDK_ACTION_COPY;
 }
 
 /* We display the cursor when
index a6cb66ceb5a4b2516da6ca6de1c2a5da21adb383..032bc620e50c264d054709fa7ea457b57a02442f 100644 (file)
@@ -423,17 +423,16 @@ static GtkTextBuffer* gtk_text_view_create_buffer (GtkTextView   *text_view);
 
 /* Target side drag signals */
 static void     gtk_text_view_drag_leave         (GtkDropTarget    *dest,
-                                                  GdkDrop          *drop,
                                                   GtkTextView      *text_view);
-static gboolean gtk_text_view_drag_motion        (GtkDropTarget    *dest,
-                                                  GdkDrop          *drop,
-                                                  int               x,
-                                                  int               y,
+static GdkDragAction
+                gtk_text_view_drag_motion        (GtkDropTarget    *dest,
+                                                  double            x,
+                                                  double            y,
                                                   GtkTextView      *text_view);
 static gboolean gtk_text_view_drag_drop          (GtkDropTarget    *dest,
-                                                  GdkDrop          *drop,
-                                                  int               x,
-                                                  int               y,
+                                                  const GValue     *value,
+                                                  double            x,
+                                                  double            y,
                                                   GtkTextView      *text_view);
 
 static gboolean gtk_text_view_popup_menu         (GtkWidget     *widget);
@@ -1752,10 +1751,11 @@ gtk_text_view_init (GtkTextView *text_view)
 
   priv->scroll_after_paste = FALSE;
 
-  dest = gtk_drop_target_new (gdk_content_formats_new_for_gtype (GTK_TYPE_TEXT_BUFFER), GDK_ACTION_COPY | GDK_ACTION_MOVE);
-  g_signal_connect (dest, "drag-leave", G_CALLBACK (gtk_text_view_drag_leave), text_view);
-  g_signal_connect (dest, "drag-motion", G_CALLBACK (gtk_text_view_drag_motion), text_view);
-  g_signal_connect (dest, "drag-drop", G_CALLBACK (gtk_text_view_drag_drop), text_view);
+  dest = gtk_drop_target_new (G_TYPE_STRING, GDK_ACTION_COPY | GDK_ACTION_MOVE);
+  g_signal_connect (dest, "enter", G_CALLBACK (gtk_text_view_drag_motion), text_view);
+  g_signal_connect (dest, "motion", G_CALLBACK (gtk_text_view_drag_motion), text_view);
+  g_signal_connect (dest, "leave", G_CALLBACK (gtk_text_view_drag_leave), text_view);
+  g_signal_connect (dest, "drop", G_CALLBACK (gtk_text_view_drag_drop), text_view);
   gtk_widget_add_controller (GTK_WIDGET (text_view), GTK_EVENT_CONTROLLER (dest));
 
   controller = gtk_drop_controller_motion_new ();
@@ -7788,7 +7788,6 @@ gtk_text_view_start_selection_dnd (GtkTextView       *text_view,
 
 static void
 gtk_text_view_drag_leave (GtkDropTarget *dest,
-                          GdkDrop       *drop,
                           GtkTextView   *text_view)
 {
   GtkTextViewPrivate *priv = text_view->priv;
@@ -7796,11 +7795,10 @@ gtk_text_view_drag_leave (GtkDropTarget *dest,
   gtk_text_mark_set_visible (priv->dnd_mark, FALSE);
 }
 
-static gboolean
+static GdkDragAction
 gtk_text_view_drag_motion (GtkDropTarget *dest,
-                           GdkDrop       *drop,
-                           int            x,
-                           int            y,
+                           double         x,
+                           double         y,
                            GtkTextView   *text_view)
 {
   GtkTextViewPrivate *priv = text_view->priv;
@@ -7834,117 +7832,50 @@ gtk_text_view_drag_motion (GtkDropTarget *dest,
   if (can_accept)
     {
       gtk_text_mark_set_visible (priv->dnd_mark, cursor_visible (text_view));
-      gdk_drop_status (drop, GDK_ACTION_COPY | GDK_ACTION_MOVE);
+      if (text_view->priv->drag)
+        return GDK_ACTION_MOVE;
+      else
+        return GDK_ACTION_COPY;
     }
   else
     {
-      gdk_drop_status (drop, 0);
       gtk_text_mark_set_visible (priv->dnd_mark, FALSE);
+      return 0;
     }
-
-  /* TRUE return means don't propagate the drag motion to parent
-   * widgets that may also be drop sites.
-   */
-  return TRUE;
 }
 
-static GdkDragAction
-gtk_text_view_get_action (GtkTextView *textview,
-                          GdkDrop     *drop)
-{
-  GdkDrag *drag = gdk_drop_get_drag (drop);
-  GdkDragAction actions;
-
-  actions = gdk_drop_get_actions (drop);
-
-  if (drag == textview->priv->drag &&
-      actions & GDK_ACTION_MOVE)
-    return GDK_ACTION_MOVE;
-
-  if (actions & GDK_ACTION_COPY)
-    return GDK_ACTION_COPY;
-
-  if (actions & GDK_ACTION_MOVE)
-    return GDK_ACTION_MOVE;
-
-  return 0;
-}
-
-static void
-got_text (GObject *source,
-          GAsyncResult *result,
-          gpointer data)
+static gboolean
+gtk_text_view_drag_drop (GtkDropTarget *dest,
+                         const GValue  *value,
+                         double         x,
+                         double         y,
+                         GtkTextView   *text_view)
 {
-  GdkDrop *drop = GDK_DROP (source);
-  GtkTextView *text_view = GTK_TEXT_VIEW (data);
   GtkTextViewPrivate *priv = text_view->priv;
   GtkTextBuffer *buffer;
-  char *str;
   GtkTextIter drop_point;
-  GdkDragAction action;
-
-  str = gdk_drop_read_text_finish (drop, result, NULL);
-  if (!str)
-    {
-      gdk_drop_finish (drop, 0);
-      return;
-    }
 
   buffer = get_buffer (text_view);
   gtk_text_buffer_get_iter_at_mark (buffer, &drop_point, priv->dnd_mark);
 
-  action = gtk_text_view_get_action (text_view, drop);
+  if (!gtk_text_iter_can_insert (&drop_point, priv->editable))
+    return FALSE;
 
   gtk_text_buffer_begin_user_action (buffer);
 
   if (!gtk_text_buffer_insert_interactive (buffer,
-                                           &drop_point, (gchar *) str, -1,
+                                           &drop_point, (gchar *) g_value_get_string (value), -1,
                                            text_view->priv->editable))
     gtk_widget_error_bell (GTK_WIDGET (text_view));
 
-  g_free (str);
-
   gtk_text_buffer_get_iter_at_mark (buffer, &drop_point, priv->dnd_mark);
   gtk_text_buffer_place_cursor (buffer, &drop_point);
 
   gtk_text_buffer_end_user_action (buffer);
 
-  gdk_drop_finish (drop, action);
-}
-
-static gboolean
-gtk_text_view_drag_drop (GtkDropTarget *dest,
-                         GdkDrop       *drop,
-                         int            x,
-                         int            y,
-                         GtkTextView *text_view)
-{
-  GtkTextViewPrivate *priv = text_view->priv;
-  GtkTextIter drop_point;
-  GtkTextBuffer *buffer = NULL;
-
-  gtk_text_mark_set_visible (priv->dnd_mark, FALSE);
-
-  buffer = get_buffer (text_view);
-  gtk_text_buffer_get_iter_at_mark (buffer, &drop_point, priv->dnd_mark);
-  
-  if (!gtk_text_iter_can_insert (&drop_point, priv->editable))
-    goto done;
-
-  if (gtk_text_view_get_action (text_view, drop) == 0)
-    goto done;
-
-  if (gdk_drop_has_value (drop, G_TYPE_STRING))
-    {
-       gdk_drop_read_text_async (drop, NULL, got_text, text_view);
-       return TRUE;
-    }
-
-done:
-  gdk_drop_finish (drop, 0);
   return TRUE;
 }
-        
+
 static void
 gtk_text_view_set_hadjustment (GtkTextView   *text_view,
                                GtkAdjustment *adjustment)
index e56c489d9b1b3b7a1b0f79c1562a5bee91617e7a..a966c8ef0ea252002e1ade927a68e6fe63711a49 100644 (file)
@@ -31,9 +31,9 @@
 #include "gtkcssnumbervalueprivate.h"
 #include "gtkcsscolorvalueprivate.h"
 #include "gtkcssstylepropertyprivate.h"
-#include "gtkdragdest.h"
 #include "gtkdragsource.h"
 #include "gtkdragicon.h"
+#include "gtkdroptargetasync.h"
 #include "gtkentryprivate.h"
 #include "gtksearchentryprivate.h"
 #include "gtkeventcontrollerkey.h"
@@ -311,7 +311,7 @@ struct _TreeViewDragInfo
   GtkTreeRowReference *source_item;
 
   GtkCssNode *cssnode;
-  GtkDropTarget *dest;
+  GtkDropTargetAsync *dest;
   GdkModifierType start_button_mask;
 
   guint source_set : 1;
@@ -667,8 +667,8 @@ static void     gtk_tree_view_key_controller_key_released (GtkEventControllerKey
                                                            guint                  keycode,
                                                            GdkModifierType        state,
                                                            GtkTreeView           *tree_view);
-static void     gtk_tree_view_focus_controller_focus_out  (GtkEventController   *focus,
-                                                           GtkTreeView            *tree_view);
+static void     gtk_tree_view_focus_controller_focus_out  (GtkEventController    *focus,
+                                                           GtkTreeView           *tree_view);
 
 static gint     gtk_tree_view_focus                (GtkWidget        *widget,
                                                    GtkDirectionType  direction);
@@ -690,22 +690,22 @@ static GdkContentProvider * gtk_tree_view_drag_data_get   (GtkTreeView
                                                            GtkTreePath           *source_row);
 
 /* Target side drag signals */
-static void     gtk_tree_view_drag_leave         (GtkDropTarget    *dest,
-                                                  GdkDrop          *drop,
-                                                  GtkTreeView      *tree_view);
-static void     gtk_tree_view_drag_motion        (GtkDropTarget    *dest,
-                                                  GdkDrop          *drop,
-                                                  int               x,
-                                                  int               y,
-                                                  GtkTreeView      *tree_view);
-static gboolean gtk_tree_view_drag_drop          (GtkDropTarget    *dest,
-                                                  GdkDrop          *drop,
-                                                  int               x,
-                                                  int               y,
-                                                  GtkTreeView      *tree_view);
-static void     gtk_tree_view_drag_data_received (GObject      *source,
-                                                  GAsyncResult *result,
-                                                  gpointer      data);
+static void     gtk_tree_view_drag_leave                  (GtkDropTargetAsync    *dest,
+                                                           GdkDrop               *drop,
+                                                           GtkTreeView           *tree_view);
+static GdkDragAction gtk_tree_view_drag_motion            (GtkDropTargetAsync    *dest,
+                                                           GdkDrop               *drop,
+                                                           double                 x,
+                                                           double                 y,
+                                                           GtkTreeView           *tree_view);
+static gboolean gtk_tree_view_drag_drop                   (GtkDropTargetAsync    *dest,
+                                                           GdkDrop               *drop,
+                                                           double                 x,
+                                                           double                 y,
+                                                           GtkTreeView           *tree_view);
+static void     gtk_tree_view_drag_data_received          (GObject               *source,
+                                                           GAsyncResult          *result,
+                                                           gpointer               data);
 
 /* tree_model signals */
 static gboolean gtk_tree_view_real_move_cursor            (GtkTreeView     *tree_view,
@@ -6859,13 +6859,13 @@ scroll_row_timeout (gpointer data)
 
 /* Returns TRUE if event should not be propagated to parent widgets */
 static gboolean
-set_destination_row (GtkTreeView    *tree_view,
-                     GtkDropTarget  *dest,
+set_destination_row (GtkTreeView         *tree_view,
+                     GtkDropTargetAsync  *dest,
                      /* coordinates relative to the widget */
-                     gint            x,
-                     gint            y,
-                     GdkDragAction  *suggested_action,
-                     GType          *target)
+                     gint                 x,
+                     gint                 y,
+                     GdkDragAction       *suggested_action,
+                     GType               *target)
 {
   GtkTreePath *path = NULL;
   GtkTreeViewDropPosition pos;
@@ -6899,7 +6899,7 @@ set_destination_row (GtkTreeView    *tree_view,
       return FALSE; /* no longer a drop site */
     }
 
-  formats = gtk_drop_target_get_formats (dest);
+  formats = gtk_drop_target_async_get_formats (dest);
   *target = gdk_content_formats_match_gtype (formats, formats);
   if (*target == G_TYPE_INVALID)
     return FALSE;
@@ -7195,9 +7195,9 @@ gtk_tree_view_drag_data_get (GtkTreeView *tree_view,
 }
 
 static void
-gtk_tree_view_drag_leave (GtkDropTarget *dest,
-                          GdkDrop       *drop,
-                          GtkTreeView   *tree_view)
+gtk_tree_view_drag_leave (GtkDropTargetAsync *dest,
+                          GdkDrop            *drop,
+                          GtkTreeView        *tree_view)
 {
   /* unset any highlight row */
   gtk_tree_view_set_drag_dest_row (tree_view,
@@ -7212,12 +7212,12 @@ gtk_tree_view_drag_leave (GtkDropTarget *dest,
 }
 
 
-static void
-gtk_tree_view_drag_motion (GtkDropTarget *dest,
-                           GdkDrop       *drop,
-                           int            x,
-                           int            y,
-                           GtkTreeView   *tree_view)
+static GdkDragAction
+gtk_tree_view_drag_motion (GtkDropTargetAsync *dest,
+                           GdkDrop            *drop,
+                           double              x,
+                           double              y,
+                           GtkTreeView        *tree_view)
 {
   gboolean empty;
   GtkTreePath *path = NULL;
@@ -7226,10 +7226,7 @@ gtk_tree_view_drag_motion (GtkDropTarget *dest,
   GType target;
 
   if (!set_destination_row (tree_view, dest, x, y, &suggested_action, &target))
-    {
-      gdk_drop_status (drop, 0);
-      return;
-    }
+    return 0;
 
   tree_view->event_last_x = x;
   tree_view->event_last_y = y;
@@ -7241,8 +7238,7 @@ gtk_tree_view_drag_motion (GtkDropTarget *dest,
 
   if (path == NULL && !empty)
     {
-      /* Can't drop here. */
-      gdk_drop_status (drop, 0);
+      suggested_action = 0;
     }
   else
     {
@@ -7270,21 +7266,22 @@ gtk_tree_view_drag_motion (GtkDropTarget *dest,
       else
         {
           set_status_pending (drop, 0);
-          gdk_drop_status (drop, suggested_action);
         }
     }
 
   if (path)
     gtk_tree_path_free (path);
+
+  return suggested_action;
 }
 
 
 static gboolean
-gtk_tree_view_drag_drop (GtkDropTarget *dest,
-                         GdkDrop       *drop,
-                         int            x,
-                         int            y,
-                         GtkTreeView   *tree_view)
+gtk_tree_view_drag_drop (GtkDropTargetAsync *dest,
+                         GdkDrop            *drop,
+                         double              x,
+                         double              y,
+                         GtkTreeView        *tree_view)
 {
   GtkTreePath *path;
   GdkDragAction suggested_action = 0;
@@ -7436,8 +7433,6 @@ gtk_tree_view_drag_data_received (GObject      *source,
             }
         }
 
-      gdk_drop_status (drop, suggested_action);
-
       if (path)
         gtk_tree_path_free (path);
 
@@ -12869,10 +12864,11 @@ gtk_tree_view_enable_model_drag_dest (GtkTreeView       *tree_view,
   di = ensure_info (tree_view);
   di->dest_set = TRUE;
 
-  di->dest = gtk_drop_target_new (gdk_content_formats_ref (formats), actions);
+  di->dest = gtk_drop_target_async_new (gdk_content_formats_ref (formats), actions);
   g_signal_connect (di->dest, "drag-leave", G_CALLBACK (gtk_tree_view_drag_leave), tree_view);
+  g_signal_connect (di->dest, "drag-enter", G_CALLBACK (gtk_tree_view_drag_motion), tree_view);
   g_signal_connect (di->dest, "drag-motion", G_CALLBACK (gtk_tree_view_drag_motion), tree_view);
-  g_signal_connect (di->dest, "drag-drop", G_CALLBACK (gtk_tree_view_drag_drop), tree_view);
+  g_signal_connect (di->dest, "drop", G_CALLBACK (gtk_tree_view_drag_drop), tree_view);
   gtk_widget_add_controller (GTK_WIDGET (tree_view), GTK_EVENT_CONTROLLER (di->dest));
   g_object_ref (di->dest);
 
index 736bc8df15f44e4a288f6b0110db12e273420b7a..0a28d8385de0bb0d6051c02868c545c2b7718dce 100644 (file)
@@ -5489,7 +5489,7 @@ gtk_widget_has_grab (GtkWidget *widget)
 {
   GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget);
 
-  g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
+  if (!GTK_IS_WIDGET (widget)) return FALSE;
 
   return priv->has_grab;
 }
index 58fd4649122756c655de655d9bab6c4db62d5429..2f6b536499a4d089002c4e33141ca30253d7c950 100644 (file)
@@ -40,7 +40,7 @@
 #include "gtkcsscolorvalueprivate.h"
 #include "gtkcssshadowvalueprivate.h"
 #include "gtkcssstylepropertyprivate.h"
-#include "gtkdragdest.h"
+#include "gtkdroptargetasync.h"
 #include "gtkeventcontrollerfocus.h"
 #include "gtkeventcontrollerkey.h"
 #include "gtkeventcontrollermotion.h"
@@ -280,12 +280,6 @@ typedef struct
   GtkConstraintSolver *constraint_solver;
 } GtkWindowPrivate;
 
-#ifdef GDK_WINDOWING_X11
-static const char *dnd_dest_targets [] = {
-  "application/x-rootwindow-drop"
-};
-#endif
-
 enum {
   SET_FOCUS,
   ACTIVATE_FOCUS,
@@ -1767,6 +1761,18 @@ gtk_window_activate_default_activate (GtkWidget  *widget,
   gtk_window_real_activate_default (GTK_WINDOW (widget));
 }
 
+static gboolean
+gtk_window_accept_rootwindow_drop (GtkDropTargetAsync *self,
+                                   GdkDrop            *drop,
+                                   double              x,
+                                   double              y,
+                                   gpointer            unused)
+{
+  gdk_drop_finish (drop, GDK_ACTION_MOVE);
+
+  return TRUE;
+}
+
 static void
 gtk_window_init (GtkWindow *window)
 {
@@ -1776,9 +1782,7 @@ gtk_window_init (GtkWindow *window)
   GdkSeat *seat;
   GtkEventController *motion_controller;
   GtkEventController *controller;
-#ifdef GDK_WINDOWING_X11
-  GtkDropTarget *dest;
-#endif
+  GtkDropTargetAsync *target;
 
   widget = GTK_WIDGET (window);
 
@@ -1829,10 +1833,10 @@ gtk_window_init (GtkWindow *window)
 
   priv->scale = gtk_widget_get_scale_factor (widget);
 
-#ifdef GDK_WINDOWING_X11
-  dest = gtk_drop_target_new (gdk_content_formats_new (dnd_dest_targets, G_N_ELEMENTS (dnd_dest_targets)), GDK_ACTION_MOVE);
-  gtk_widget_add_controller (GTK_WIDGET (window), GTK_EVENT_CONTROLLER (dest));
-#endif
+  target = gtk_drop_target_async_new (gdk_content_formats_new ((const char*[1]) { "application/x-rootwindow-drop" }, 1),
+                                      GDK_ACTION_MOVE);
+  g_signal_connect (target, "drop", G_CALLBACK (gtk_window_accept_rootwindow_drop), NULL);
+  gtk_widget_add_controller (GTK_WIDGET (window), GTK_EVENT_CONTROLLER (target));
 
   seat = gdk_display_get_default_seat (gtk_widget_get_display (widget));
   g_signal_connect (seat, "device-removed",
index ca72c0210126297d6f68168788f646a234346f6c..d68b54539cdbf7f93a465937a27b03fb7bb4e81a 100644 (file)
@@ -98,6 +98,7 @@ gtk_private_sources = files([
   'gtkcssvalue.c',
   'gtkcsswidgetnode.c',
   'gtkcustomlayout.c',
+  'gtkdrop.c',
   'gtkfilechooserembed.c',
   'gtkfilechooserentry.c',
   'gtkfilechoosererrorstack.c',
@@ -207,11 +208,12 @@ gtk_public_sources = files([
   'gtkcontainer.c',
   'gtkcssprovider.c',
   'gtkdialog.c',
-  'gtkdragdest.c',
   'gtkdragicon.c',
   'gtkdragsource.c',
   'gtkdrawingarea.c',
   'gtkdropcontrollermotion.c',
+  'gtkdroptarget.c',
+  'gtkdroptargetasync.c',
   'gtkeditable.c',
   'gtkemojichooser.c',
   'gtkemojicompletion.c',
@@ -457,11 +459,12 @@ gtk_public_headers = files([
   'gtkcustomlayout.h',
   'gtkdebug.h',
   'gtkdialog.h',
-  'gtkdragdest.h',
   'gtkdragicon.h',
   'gtkdragsource.h',
   'gtkdrawingarea.h',
   'gtkdropcontrollermotion.h',
+  'gtkdroptarget.h',
+  'gtkdroptargetasync.h',
   'gtkeditable.h',
   'gtkemojichooser.h',
   'gtkentry.h',
index f48a55b6af9433ad94a00e4147f37faf4062dd45..ec1a5c2a08b566d28487f1af09ff3435cfb7d519 100644 (file)
@@ -287,138 +287,87 @@ static const char * trashcan_open_xpm[] = {
 GdkPixbuf *trashcan_open;
 GdkPixbuf *trashcan_closed;
 
-gboolean have_drag;
 
-static const char *target_table[] = {
-  "STRING",
-  "text/plain",
-  "application/x-rootwindow-drop"
-};
+static GdkDragAction
+action_make_unique (GdkDragAction action)
+{
+  if (gdk_drag_action_is_unique (action))
+    return action;
 
-static guint n_targets = sizeof(target_table) / sizeof(target_table[0]);
+  if (action & GDK_ACTION_COPY)
+    return GDK_ACTION_COPY;
 
-void  
-target_drag_leave (GtkDropTarget *dest,
-                   GdkDrop       *drop,
-                   GtkWidget     *widget)
-{
-  g_print("leave\n");
-  have_drag = FALSE;
-  gtk_image_set_from_pixbuf (GTK_IMAGE (widget), trashcan_closed);
+  if (action & GDK_ACTION_MOVE)
+    return GDK_ACTION_MOVE;
+  
+  if (action & GDK_ACTION_LINK)
+    return GDK_ACTION_LINK;
+  
+  g_assert_not_reached ();
+  return 0;
 }
 
-gboolean
-target_drag_motion (GtkDropTarget *dest,
-                    GdkDrop       *drop,
-                    int            x,
-                    int            y,
-                    GtkWidget     *widget) 
+GdkDragAction
+trash_drag_enter (GtkDropTarget *dest,
+                  GdkDrop       *drop,
+                  double         x,
+                  double         y,
+                  GtkWidget     *widget) 
 {
   char *s;
 
-  if (!have_drag)
-    {
-      have_drag = TRUE;
-      gtk_image_set_from_pixbuf (GTK_IMAGE (widget), trashcan_open);
-    }
+  gtk_image_set_from_pixbuf (GTK_IMAGE (widget), trashcan_open);
 
   s = gdk_content_formats_to_string (gdk_drop_get_formats (drop));
-  g_print ("%s\n", s);
-
-  gdk_drop_status (drop, GDK_ACTION_ALL);
+  g_print ("trash enter: %s\n", s);
+  g_free (s);
 
-  return TRUE;
+  return action_make_unique (gdk_drop_get_actions (drop));;
 }
 
-static void
-got_text_in_target (GObject *object,
-                    GAsyncResult *result,
-                    gpointer data)
-{
-  char *str;
-
-  str = gdk_drop_read_text_finish (GDK_DROP (object), result, NULL);
-  if (str)
-    {
-      g_print ("Received \"%s\" in target\n", str);
-      g_free (str);
-    }
-
-  gdk_drop_finish (GDK_DROP (object), GDK_ACTION_MOVE);
-}
-gboolean
-target_drag_drop (GtkDropTarget *dest,
+GdkDragAction
+trash_drag_leave (GtkDropTarget *dest,
                   GdkDrop       *drop,
-                  int            x,
-                  int            y,
-                  GtkWidget     *widget)
+                  GtkWidget     *widget) 
 {
-  GdkContentFormats *formats;
-  const char *format;
-
-  g_print("drop\n");
-  have_drag = FALSE;
+  char *s;
 
   gtk_image_set_from_pixbuf (GTK_IMAGE (widget), trashcan_closed);
 
-  formats = gdk_drop_get_formats (drop);
-  format = gdk_content_formats_match_mime_type (formats, formats);
-  if (format)
-    {
-      gdk_drop_read_text_async (drop, NULL, got_text_in_target, widget);
-      return TRUE;
-    }
-  
-  gdk_drop_status (drop, 0);
+  s = gdk_content_formats_to_string (gdk_drop_get_formats (drop));
+  g_print ("trash leave: %s\n", s);
+  g_free (s);
 
-  return FALSE;
+  return action_make_unique (gdk_drop_get_actions (drop));
 }
 
-static GdkDragAction
-action_make_unique (GdkDragAction action)
+gboolean
+trash_drag_drop (GtkDropTarget *dest,
+                 GdkDrop       *drop,
+                 double         x,
+                 double         y,
+                 GtkWidget     *widget)
 {
-  if (gdk_drag_action_is_unique (action))
-    return action;
-
-  if (action & GDK_ACTION_COPY)
-    return GDK_ACTION_COPY;
+  char *s;
 
-  if (action & GDK_ACTION_MOVE)
-    return GDK_ACTION_MOVE;
-  
-  if (action & GDK_ACTION_LINK)
-    return GDK_ACTION_LINK;
-  
-  g_assert_not_reached ();
-  return 0;
-}
+  s = gdk_content_formats_to_string (gdk_drop_get_formats (drop));
+  g_print ("trash drop: %s\n", s);
+  g_free (s);
 
-static void
-got_text (GObject *object,
-          GAsyncResult *result,
-          gpointer data)
-{
-  char *str;
+  gdk_drop_finish (drop, action_make_unique (gdk_drop_get_actions (drop)));
 
-  str = gdk_drop_read_text_finish (GDK_DROP (object), result, NULL);
-  if (str)
-    {
-      g_print ("Received \"%s\" in label\n", str);
-      g_free (str);
-    }
+  return TRUE;
 }
-void  
+
+gboolean
 label_drag_drop (GtkDropTarget *dest,
-                 GdkDrop       *drop,
+                 const GValue  *value,
                  int            x,
                  int            y,
                  GtkWidget     *widget)
 {
-  gdk_drop_read_text_async (drop, NULL, got_text, widget);
-  GdkDragAction action = action_make_unique (gdk_drop_get_actions (drop));
-  gdk_drop_finish (drop, action);
+  g_print ("Received \"%s\" in label\n", g_value_get_string (value));
+  return TRUE;
 }
 
 /* The following is a rather elaborate example demonstrating/testing
@@ -443,18 +392,10 @@ popdown_cb (gpointer data)
   return FALSE;
 }
 
-gboolean
-popup_motion (GtkDropTarget *dest,
-              GdkDrop       *drop)
-{
-  gdk_drop_status (drop, GDK_ACTION_COPY);
-  return TRUE;
-}
-
 void  
 popup_enter (GtkDropTarget *dest)
 {
-g_print ("popup enter\n");
+  g_print ("popup enter\n");
   if (!in_popup)
     {
       in_popup = TRUE;
@@ -483,10 +424,8 @@ g_print ("popup leave\n");
 }
 
 static gboolean
-popup_drop (GtkDropTarget *dest,
-            GdkDrop       *drop)
+popup_drop (GtkDropTarget *dest)
 {
-  gdk_drop_finish (drop, GDK_ACTION_COPY);
   popdown_cb (NULL);
   return TRUE;
 }
@@ -501,12 +440,10 @@ popup_cb (gpointer data)
          GtkWidget *button;
          GtkWidget *grid;
          int i, j;
-          GdkContentFormats *targets;
          
          popup_window = gtk_window_new ();
 
          grid = gtk_grid_new ();
-          targets = gdk_content_formats_new_for_gtype (G_TYPE_STRING);
 
          for (i=0; i<3; i++)
            for (j=0; j<3; j++)
@@ -520,16 +457,13 @@ popup_cb (gpointer data)
                 gtk_widget_set_vexpand (button, TRUE);
                gtk_grid_attach (GTK_GRID (grid), button, i, j, 1, 1);
 
-                dest = gtk_drop_target_new (targets, GDK_ACTION_COPY | GDK_ACTION_MOVE);
-               g_signal_connect (dest, "accept", G_CALLBACK (popup_motion), NULL);
-               g_signal_connect (dest, "drag-enter", G_CALLBACK (popup_enter), NULL);
-               g_signal_connect (dest, "drag-leave", G_CALLBACK (popup_leave), NULL);
-               g_signal_connect (dest, "drag-drop", G_CALLBACK (popup_drop), NULL);
+                dest = gtk_drop_target_new (G_TYPE_STRING, GDK_ACTION_COPY | GDK_ACTION_MOVE);
+               g_signal_connect (dest, "enter", G_CALLBACK (popup_enter), NULL);
+               g_signal_connect (dest, "leave", G_CALLBACK (popup_leave), NULL);
+               g_signal_connect (dest, "drop", G_CALLBACK (popup_drop), NULL);
                 gtk_widget_add_controller (button, GTK_EVENT_CONTROLLER (dest));
              }
          gtk_container_add (GTK_CONTAINER (popup_window), grid);
-          gdk_content_formats_unref (targets);
-
        }
       gtk_widget_show (popup_window);
       popped_up = TRUE;
@@ -550,18 +484,17 @@ popsite_motion (GtkDropTarget *dest,
 }
 
 void  
-popsite_enter (GtkDropTarget *dest)
+popsite_enter (GtkDropControllerMotion *motion)
 {
-g_print ("popsite enter\n");
+  g_print ("popsite enter\n");
   if (!popup_timer)
     popup_timer = g_timeout_add (500, popup_cb, NULL);
-
 }
 
 void  
-popsite_leave (GtkDropTarget *dest)
+popsite_leave (GtkDropControllerMotion *motion)
 {
-g_print ("popsite leave\n");
+  g_print ("popsite leave\n");
   if (popup_timer)
     {
       g_source_remove (popup_timer);
@@ -606,8 +539,9 @@ main (int argc, char **argv)
   GdkTexture *texture;
   GdkContentProvider *content;
   GtkDragSource *source;
-  GdkContentFormats *targets;
   GtkDropTarget *dest;
+  GtkDropTargetAsync *async;
+  GtkEventController *controller;
   gboolean done = FALSE;
 
   test_init ();
@@ -630,9 +564,8 @@ main (int argc, char **argv)
   
   label = gtk_label_new ("Drop Here\n");
 
-  targets = gdk_content_formats_new (target_table, n_targets - 1); /* no rootwin */
-  dest = gtk_drop_target_new (gdk_content_formats_ref (targets), GDK_ACTION_COPY | GDK_ACTION_MOVE);
-  g_signal_connect (dest, "drag-drop", G_CALLBACK (label_drag_drop), NULL);
+  dest = gtk_drop_target_new (G_TYPE_STRING, GDK_ACTION_COPY | GDK_ACTION_MOVE);
+  g_signal_connect (dest, "drop", G_CALLBACK (label_drag_drop), NULL);
   gtk_widget_add_controller (label, GTK_EVENT_CONTROLLER (dest));
 
   gtk_widget_set_hexpand (label, TRUE);
@@ -641,22 +574,21 @@ main (int argc, char **argv)
 
   label = gtk_label_new ("Popup\n");
 
-  dest = gtk_drop_target_new (targets, GDK_ACTION_COPY | GDK_ACTION_MOVE);
-  g_signal_connect (dest, "accept", G_CALLBACK (popsite_motion), NULL);
-  g_signal_connect (dest, "drag-enter", G_CALLBACK (popsite_enter), NULL);
-  g_signal_connect (dest, "drag-leave", G_CALLBACK (popsite_leave), NULL);
-  gtk_widget_add_controller (label, GTK_EVENT_CONTROLLER (dest));
+  controller = gtk_drop_controller_motion_new ();
+  g_signal_connect (controller, "enter", G_CALLBACK (popsite_enter), NULL);
+  g_signal_connect (controller, "leave", G_CALLBACK (popsite_leave), NULL);
+  gtk_widget_add_controller (label, controller);
 
   gtk_widget_set_hexpand (label, TRUE);
   gtk_widget_set_vexpand (label, TRUE);
   gtk_grid_attach (GTK_GRID (grid), label, 1, 1, 1, 1);
 
   pixmap = gtk_image_new_from_pixbuf (trashcan_closed);
-  dest = gtk_drop_target_new (NULL, 0);
-  g_signal_connect (dest, "drag-leave", G_CALLBACK (target_drag_leave), pixmap);
-  g_signal_connect (dest, "accept", G_CALLBACK (target_drag_motion), pixmap);
-  g_signal_connect (dest, "drag-drop", G_CALLBACK (target_drag_drop), pixmap);
-  gtk_widget_add_controller (pixmap, GTK_EVENT_CONTROLLER (dest));
+  async = gtk_drop_target_async_new (NULL, 0);
+  g_signal_connect (async, "drag-enter", G_CALLBACK (trash_drag_enter), pixmap);
+  g_signal_connect (async, "drag-leave", G_CALLBACK (trash_drag_leave), pixmap);
+  g_signal_connect (async, "drop", G_CALLBACK (trash_drag_drop), pixmap);
+  gtk_widget_add_controller (pixmap, GTK_EVENT_CONTROLLER (async));
 
   gtk_widget_set_hexpand (pixmap, TRUE);
   gtk_widget_set_vexpand (pixmap, TRUE);
index 17b1abcbbb68ae01c9b1fc470bc3e24aed1da440..2294b2539ede440d8ba240aa31c91fefcf275c51 100644 (file)
@@ -128,7 +128,7 @@ static void
 perform_drop (GdkDrop   *drop,
               GtkWidget *image)
 {
-  if (gdk_drop_has_value (drop, GDK_TYPE_TEXTURE))
+  if (gdk_content_formats_contain_gtype (gdk_drop_get_formats (drop), GDK_TYPE_TEXTURE))
     gdk_drop_read_value_async (drop, GDK_TYPE_TEXTURE, G_PRIORITY_DEFAULT, NULL, got_texture, image);
   else
     {
@@ -192,39 +192,37 @@ ask_actions (GdkDrop *drop,
 static gboolean
 delayed_deny (gpointer data)
 {
-  GtkDropTarget *dest = data;
+  GtkDropTargetAsync *dest = data;
   GtkWidget *image = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (dest));
   GdkDrop *drop = GDK_DROP (g_object_get_data (G_OBJECT (image), "drop"));
 
   if (drop)
     {
       g_print ("denying drop, late\n");
-      gtk_drop_target_deny_drop (dest, drop);
+      gtk_drop_target_async_reject_drop (dest, drop);
     }
 
   return G_SOURCE_REMOVE;
 }
 
 static gboolean
-image_drag_motion (GtkDropTarget    *dest,
-                   GdkDrop          *drop,
-                   gpointer          data)
+image_drag_accept (GtkDropTargetAsync *dest,
+                   GdkDrop            *drop,
+                   gpointer            data)
 {
   GtkWidget *image = data;
   g_object_set_data_full (G_OBJECT (image), "drop", g_object_ref (drop), g_object_unref);
 
   g_timeout_add (1000, delayed_deny, dest);
 
-  gdk_drop_status (drop, gtk_drop_target_get_actions (dest));
-
   return TRUE;
 }
 
 static gboolean
 image_drag_drop (GtkDropTarget    *dest,
                  GdkDrop          *drop,
-                 int               x,
-                 int               y,
+                 double            x,
+                 double            y,
                  gpointer          data)
 {
   GtkWidget *image = data;
@@ -330,7 +328,7 @@ make_image (const gchar *icon_name, int hotspot)
 {
   GtkWidget *image;
   GtkDragSource *source;
-  GtkDropTarget *dest;
+  GtkDropTargetAsync *dest;
   GdkContentFormats *formats;
   GdkContentFormatsBuilder *builder;
 
@@ -352,9 +350,9 @@ make_image (const gchar *icon_name, int hotspot)
   g_signal_connect (source, "drag-cancel", G_CALLBACK (drag_cancel), NULL);
   gtk_widget_add_controller (image, GTK_EVENT_CONTROLLER (source));
 
-  dest = gtk_drop_target_new (formats, GDK_ACTION_COPY|GDK_ACTION_MOVE|GDK_ACTION_ASK);
-  g_signal_connect (dest, "accept", G_CALLBACK (image_drag_motion), image);
-  g_signal_connect (dest, "drag-drop", G_CALLBACK (image_drag_drop), image);
+  dest = gtk_drop_target_async_new (formats, GDK_ACTION_COPY|GDK_ACTION_MOVE|GDK_ACTION_ASK);
+  g_signal_connect (dest, "accept", G_CALLBACK (image_drag_accept), image);
+  g_signal_connect (dest, "drop", G_CALLBACK (image_drag_drop), image);
   gtk_widget_add_controller (image, GTK_EVENT_CONTROLLER (dest));
 
   return image;
index 4b58ad136b3b9bfba1b0e4d0ef3a0effc7e94748..795445f65c7e2f2c1d406976b05f92692f0e78bd 100644 (file)
@@ -50,12 +50,6 @@ drag_cancel (GtkDragSource       *source,
   drag_end (source, drag);
 }
 
-typedef struct {
-  GtkWidget *canvas;
-  double x;
-  double y;
-} DropData;
-
 typedef struct {
   double x, y;
   double angle;
@@ -76,32 +70,22 @@ apply_transform (GtkWidget *item)
   gsk_transform_unref (transform);
 }
 
-static void
-got_data (GObject      *source,
-          GAsyncResult *result,
-          gpointer      user_data)
+static gboolean
+drag_drop (GtkDropTarget *target,
+           const GValue  *value,
+           double         x,
+           double         y)
 {
-  GdkDrop *drop = GDK_DROP (source);
-  DropData *data = user_data;
   GtkWidget *item;
-  const GValue *value;
   TransformData *transform_data;
   GtkWidget *canvas;
   GtkWidget *last_child;
 
-  value = gdk_drop_read_value_finish (drop, result, NULL);
-  if (value == NULL)
-    {
-      gdk_drop_finish (drop, 0);
-      return;
-    }
-
   item = g_value_get_object (value);
-
   transform_data = g_object_get_data (G_OBJECT (item), "transform-data");
 
-  transform_data->x = data->x;
-  transform_data->y = data->y;
+  transform_data->x = x;
+  transform_data->y = y;
 
   canvas = gtk_widget_get_parent (item);
   last_child = gtk_widget_get_last_child (canvas);
@@ -110,26 +94,6 @@ got_data (GObject      *source,
 
   apply_transform (item);
 
-  gdk_drop_finish (drop, GDK_ACTION_MOVE);
-
-  g_free (data);
-}
-
-static gboolean
-drag_drop (GtkDropTarget *dest,
-           GdkDrop       *drop,
-           int            x,
-           int            y)
-{
-  DropData *data;
-
-  data = g_new (DropData, 1);
-  data->canvas = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (dest));
-  data->x = x;
-  data->y = y;
-
-  gdk_drop_read_value_async (drop, GTK_TYPE_WIDGET, G_PRIORITY_DEFAULT, NULL, got_data, data);
-
   return TRUE;
 }
 
@@ -153,8 +117,8 @@ canvas_new (void)
   g_signal_connect (source, "drag-cancel", G_CALLBACK (drag_cancel), NULL);
   gtk_widget_add_controller (canvas, GTK_EVENT_CONTROLLER (source));
 
-  dest = gtk_drop_target_new (gdk_content_formats_new_for_gtype (GTK_TYPE_WIDGET), GDK_ACTION_MOVE);
-  g_signal_connect (dest, "drag-drop", G_CALLBACK (drag_drop), NULL);
+  dest = gtk_drop_target_new (GTK_TYPE_WIDGET, GDK_ACTION_MOVE);
+  g_signal_connect (dest, "drop", G_CALLBACK (drag_drop), NULL);
   gtk_widget_add_controller (canvas, GTK_EVENT_CONTROLLER (dest));
 
   return canvas;
@@ -186,31 +150,16 @@ set_color (GtkWidget *item,
   g_free (css);
 }
 
-static void
-got_color (GObject *source,
-           GAsyncResult *result,
-           gpointer data)
+static gboolean
+item_drag_drop (GtkDropTarget *dest,
+                const GValue  *value,
+                double         x,
+                double         y)
 {
-  GdkDrop *drop = GDK_DROP (source);
-  GtkDropTarget *dest = data;
   GtkWidget *item = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (dest));
-  const GValue *value;
-  GdkRGBA *color;
-
-  value = gdk_drop_read_value_finish (drop, result, NULL);
-  color = g_value_get_boxed (value);
-  set_color (item, color);
 
-  gdk_drop_finish (drop, GDK_ACTION_COPY);
-}
+  set_color (item, g_value_get_boxed (value));
 
-static gboolean
-item_drag_drop (GtkDropTarget *dest,
-                GdkDrop       *drop,
-               int            x,
-               int            y)
-{
-  gdk_drop_read_value_async (drop, GDK_TYPE_RGBA, G_PRIORITY_DEFAULT, NULL, got_color, dest);
   return TRUE;
 }
 
@@ -261,7 +210,6 @@ canvas_item_new (int i,
   TransformData *transform_data;
   GdkRGBA rgba;
   GtkDropTarget *dest;
-  GdkContentFormats *formats;
   GtkGesture *gesture;
 
   label = g_strdup_printf ("Item %d", i);
@@ -283,11 +231,9 @@ canvas_item_new (int i,
   g_free (label);
   g_free (id);
 
-  formats = gdk_content_formats_new_for_gtype (GDK_TYPE_RGBA);
-  dest = gtk_drop_target_new (formats, GDK_ACTION_COPY);
-  g_signal_connect (dest, "drag-drop", G_CALLBACK (item_drag_drop), NULL);
+  dest = gtk_drop_target_new (GDK_TYPE_RGBA, GDK_ACTION_COPY);
+  g_signal_connect (dest, "drop", G_CALLBACK (item_drag_drop), NULL);
   gtk_widget_add_controller (widget, GTK_EVENT_CONTROLLER (dest));
-  gdk_content_formats_unref (formats);
 
   gesture = gtk_gesture_rotate_new ();
   g_signal_connect (gesture, "angle-changed", G_CALLBACK (angle_changed), NULL);
index 1e2825de2b6e1d27753474b51628b3beb5f0228e..88d17137162e4627fe0d6a364ec4755c46c6489e 100644 (file)
@@ -29,47 +29,30 @@ drag_begin (GtkDragSource *source,
   g_object_unref (paintable);
 }
 
-static void
-got_row (GObject      *src,
-         GAsyncResult *result,
-         gpointer      data)
+static gboolean
+drag_drop (GtkDropTarget *dest,
+           const GValue  *value,
+           double         x,
+           double         y,
+           gpointer       data)
 {
-  GdkDrop *drop = GDK_DROP (src);
   GtkWidget *target = data;
   GtkWidget *source;
   int pos;
 
-  source = g_value_get_object (gdk_drop_read_value_finish (drop, result, NULL));
+  source = g_value_get_object (value);
   if (source == NULL)
-    {
-      gdk_drop_finish (drop, 0);
-      return;
-    }
+    return FALSE;
 
   pos = gtk_list_box_row_get_index (GTK_LIST_BOX_ROW (target));
   if (source == target)
-    {
-      gdk_drop_finish (drop, 0);
-      return;
-    }
+    return FALSE;
 
   g_object_ref (source);
   gtk_container_remove (GTK_CONTAINER (gtk_widget_get_parent (source)), source);
   gtk_list_box_insert (GTK_LIST_BOX (gtk_widget_get_parent (target)), source, pos);
   g_object_unref (source);
 
-  gdk_drop_finish (drop, GDK_ACTION_MOVE);
-}
-
-static gboolean
-drag_drop (GtkDropTarget    *dest,
-           GdkDrop          *drop,
-           int               x,
-           int               y,
-           gpointer          data)
-{
-  gdk_drop_read_value_async (drop, GTK_TYPE_LIST_BOX_ROW, G_PRIORITY_DEFAULT, NULL, got_row, data);
-
   return TRUE;
 }
 
@@ -96,8 +79,8 @@ create_row (const gchar *text)
   g_signal_connect (source, "prepare", G_CALLBACK (prepare), row);
   gtk_widget_add_controller (image, GTK_EVENT_CONTROLLER (source));
 
-  dest = gtk_drop_target_new (gdk_content_formats_new_for_gtype (GTK_TYPE_LIST_BOX_ROW), GDK_ACTION_MOVE);
-  g_signal_connect (dest, "drag-drop", G_CALLBACK (drag_drop), row);
+  dest = gtk_drop_target_new (GTK_TYPE_LIST_BOX_ROW, GDK_ACTION_MOVE);
+  g_signal_connect (dest, "drop", G_CALLBACK (drag_drop), row);
   gtk_widget_add_controller (GTK_WIDGET (row), GTK_EVENT_CONTROLLER (dest));
 
   return row;
index f7050f04a9494e4ddc15bf5fe95499f9ae9a56d7..d8d8077d6362b1ac37565784a4ceb421993d04fe 100644 (file)
@@ -55,10 +55,6 @@ gchar *tabs4 [] = {
   NULL
 };
 
-static const char *button_targets[] = {
-  "GTK_NOTEBOOK_TAB"
-};
-
 static GtkNotebook*
 window_creation_function (GtkNotebook *source_notebook,
                           GtkWidget   *child,
@@ -93,7 +89,8 @@ on_page_reordered (GtkNotebook *notebook, GtkWidget *child, guint page_num, gpoi
 static gboolean
 remove_in_idle (gpointer data)
 {
-  GtkWidget *child = data;
+  GtkNotebookPage *page = data;
+  GtkWidget *child = gtk_notebook_page_get_child (page);
   GtkWidget *parent = gtk_widget_get_ancestor (child, GTK_TYPE_NOTEBOOK);
   GtkWidget *tab_label;
 
@@ -104,44 +101,17 @@ remove_in_idle (gpointer data)
   return G_SOURCE_REMOVE;
 }
 
-static void
-got_page (GObject *source,
-          GAsyncResult *result,
-          gpointer data)
-{
-  GdkDrop *drop = GDK_DROP (source);
-  GInputStream *stream;
-  const char *mime_type;
-
-  stream = gdk_drop_read_finish (drop, result, &mime_type, NULL);
-
-  if (stream)
-    {
-      GBytes *bytes;
-      GtkWidget **child;
-
-      bytes = g_input_stream_read_bytes (stream, sizeof (gpointer), NULL, NULL);
-      child = (gpointer)g_bytes_get_data (bytes, NULL);
-
-      g_idle_add (remove_in_idle, *child);
-
-      gdk_drop_finish (drop, GDK_ACTION_MOVE);
-
-      g_bytes_unref (bytes);
-      g_object_unref (stream);
-    }
-  else
-    gdk_drop_finish (drop, 0);
-}
-
 static gboolean
 on_button_drag_drop (GtkDropTarget *dest,
-                     GdkDrop       *drop,
+                     const GValue  *value,
+                     double         x,
+                     double         y,
                      gpointer       user_data)
 {
-  gdk_drop_read_async (drop, (const char *[]) { "GTK_NOTEBOOK_TAB", NULL }, G_PRIORITY_DEFAULT, NULL, got_page, NULL);
+  GtkNotebookPage *page;
 
-  gdk_drop_finish (drop, GDK_ACTION_MOVE);
+  page = g_value_get_object (value);
+  g_idle_add (remove_in_idle, page);
 
   return TRUE;
 }
@@ -298,8 +268,8 @@ create_trash_button (void)
 
   button = gtk_button_new_with_mnemonic ("_Delete");
 
-  dest = gtk_drop_target_new (gdk_content_formats_new (button_targets, G_N_ELEMENTS (button_targets)), GDK_ACTION_MOVE);
-  g_signal_connect (dest, "drag-drop", G_CALLBACK (on_button_drag_drop), NULL);
+  dest = gtk_drop_target_new (GTK_TYPE_NOTEBOOK_PAGE, GDK_ACTION_MOVE);
+  g_signal_connect (dest, "drop", G_CALLBACK (on_button_drag_drop), NULL);
   gtk_widget_add_controller (button, GTK_EVENT_CONTROLLER (dest));
 
   return button;
index c087527ce35a14d305782676573c645cb950d857..04450938e2993901985e6642ee6a8b2f6d9c0eb1 100644 (file)
@@ -84,32 +84,16 @@ get_dragsource (void)
   return GTK_WIDGET (tv);
 }
 
-static void
-got_text (GObject      *source,
-          GAsyncResult *result,
-          gpointer      data)
-{
-  GdkDrop *drop = GDK_DROP (source);
-  GtkWidget *widget = data;
-  const GValue *value;
-
-  value = gdk_drop_read_value_finish (drop, result, NULL);
-  if (value == NULL)
-    return;
-  
-  gtk_label_set_label (GTK_LABEL (widget), g_value_get_string (value));
-}
-
 static void
 drag_drop (GtkDropTarget *dest,
-           GdkDrop       *drop,
+           const GValue  *value,
            int            x,
            int            y,
            gpointer       dada)
 {
   GtkWidget *widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (dest));
 
-  gdk_drop_read_value_async (drop, G_TYPE_STRING, G_PRIORITY_DEFAULT, NULL, got_text, widget);
+  gtk_label_set_label (GTK_LABEL (widget), g_value_get_string (value));
 }
 
 static GtkWidget *
@@ -119,8 +103,8 @@ get_droptarget (void)
   GtkDropTarget *dest;
 
   label = gtk_label_new ("Drop here");
-  dest = gtk_drop_target_new (gdk_content_formats_new_for_gtype (G_TYPE_STRING), GDK_ACTION_COPY);
-  g_signal_connect (dest, "drag-drop", G_CALLBACK (drag_drop), NULL);
+  dest = gtk_drop_target_new (G_TYPE_STRING, GDK_ACTION_COPY);
+  g_signal_connect (dest, "drop", G_CALLBACK (drag_drop), NULL);
   gtk_widget_add_controller (label, GTK_EVENT_CONTROLLER (dest));
 
   return label;
index 29536fe0370e083746dd9702594f2846698af10d..ab735dc48285e288bac22d0c3ef2634cbb1af482 100644 (file)
@@ -150,7 +150,8 @@ test_type (gconstpointer data)
 
       /* These are set in init() */
       if ((g_type_is_a (type, GDK_TYPE_CLIPBOARD) ||
-           g_type_is_a (type, GDK_TYPE_CONTENT_PROVIDER)) &&
+           g_type_is_a (type, GDK_TYPE_CONTENT_PROVIDER) ||
+           g_type_is_a (type, GTK_TYPE_DROP_TARGET)) &&
          strcmp (pspec->name, "formats") == 0)
        continue;